| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.charts |
| { |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.display.Graphics; |
| import flash.display.InteractiveObject; |
| import flash.display.Loader; |
| import flash.display.Shape; |
| import flash.display.Sprite; |
| import flash.events.Event; |
| import flash.events.KeyboardEvent; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| import flash.system.ApplicationDomain; |
| import flash.text.TextField; |
| import flash.text.TextLineMetrics; |
| import flash.ui.Keyboard; |
| import flash.utils.getDefinitionByName; |
| |
| import mx.binding.BindingManager; |
| import mx.charts.chartClasses.ChartBase; |
| import mx.charts.events.LegendMouseEvent; |
| import mx.collections.ArrayCollection; |
| import mx.collections.ICollectionView; |
| import mx.collections.IList; |
| import mx.collections.ListCollectionView; |
| import mx.containers.utilityClasses.PostScaleAdapter; |
| import mx.core.ComponentDescriptor; |
| import mx.core.ContainerCreationPolicy; |
| import mx.core.ContainerGlobals; |
| import mx.core.EdgeMetrics; |
| import mx.core.FlexGlobals; |
| import mx.core.FlexSprite; |
| import mx.core.FlexVersion; |
| import mx.core.IChildList; |
| import mx.core.IContainer; |
| import mx.core.IDeferredInstantiationUIComponent; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.IFlexModuleFactory; |
| import mx.core.IInvalidating; |
| import mx.core.ILayoutDirectionElement; |
| import mx.core.IRectangularBorder; |
| import mx.core.IRepeater; |
| import mx.core.IRepeaterClient; |
| import mx.core.IUIComponent; |
| import mx.core.IUITextField; |
| import mx.core.IVisualElement; |
| import mx.core.ScrollPolicy; |
| import mx.core.UIComponent; |
| import mx.core.UIComponentDescriptor; |
| import mx.core.UIComponentGlobals; |
| import mx.core.mx_internal; |
| import mx.events.ChildExistenceChangedEvent; |
| import mx.events.FlexEvent; |
| import mx.events.IndexChangedEvent; |
| import mx.geom.RoundedRectangle; |
| import mx.managers.ILayoutManagerClient; |
| import mx.managers.ISystemManager; |
| import mx.styles.CSSStyleDeclaration; |
| import mx.styles.ISimpleStyleClient; |
| import mx.styles.IStyleClient; |
| import mx.styles.StyleProtoChain; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when the user clicks on a LegendItem in the Legend control. |
| * |
| * @eventType mx.charts.events.LegendMouseEvent.ITEM_CLICK |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="itemClick", type="mx.charts.events.LegendMouseEvent")] |
| |
| /** |
| * Dispatched when the user presses the mouse button |
| * while over a LegendItem in the Legend control. |
| * |
| * @eventType mx.charts.events.LegendMouseEvent.ITEM_MOUSE_DOWN |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="itemMouseDown", type="mx.charts.events.LegendMouseEvent")] |
| |
| /** |
| * Dispatched when the user moves the mouse off of a LegendItem in the Legend. |
| * |
| * @eventType mx.charts.events.LegendMouseEvent.ITEM_MOUSE_OUT |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="itemMouseOut", type="mx.charts.events.LegendMouseEvent")] |
| |
| /** |
| * Dispatched when the user moves the mouse over a LegendItem in the Legend control. |
| * |
| * @eventType mx.charts.events.LegendMouseEvent.ITEM_MOUSE_OVER |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="itemMouseOver", type="mx.charts.events.LegendMouseEvent")] |
| |
| /** |
| * Dispatched when the user releases the mouse button |
| * while over a LegendItem in the Legend. |
| * |
| * @eventType mx.charts.events.LegendMouseEvent.ITEM_MOUSE_UP |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="itemMouseUp", type="mx.charts.events.LegendMouseEvent")] |
| |
| /** |
| * Dispatched after a child has been added to a legend. |
| * |
| * <p>The childAdd event is dispatched when the <code>addChild()</code> |
| * or <code>addChildAt()</code> method is called. |
| * When a container is first created, the <code>addChild()</code> |
| * method is automatically called for each child component declared |
| * in the MXML file. |
| * The <code>addChildAt()</code> method is automatically called |
| * whenever a Repeater object adds or removes child objects. |
| * The application developer may also manually call these |
| * methods to add new children.</p> |
| * |
| * <p>At the time when this event is sent, the child object has been |
| * initialized, but its width and height have not yet been calculated, |
| * and the child has not been drawn on the screen. |
| * If you want to be notified when the child has been fully initialized |
| * and rendered, then register as a listener for the child's |
| * <code>creationComplete</code> event.</p> |
| * |
| * @eventType mx.events.ChildExistenceChangedEvent.CHILD_ADD |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="childAdd", type="mx.events.ChildExistenceChangedEvent")] |
| |
| /** |
| * Dispatched after the index (among the legend children) |
| * of a legend child changes. |
| * This event is only dispatched for the child specified as the argument to |
| * the <code>setChildIndex()</code> method; it is not dispatched |
| * for any other child whose index changes as a side effect of the call |
| * to the <code>setChildIndex()</code> method. |
| * |
| * <p>The child's index is changed when the |
| * <code>setChildIndex()</code> method is called.</p> |
| * |
| * @eventType mx.events.IndexChangedEvent.CHILD_INDEX_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="childIndexChange", type="mx.events.IndexChangedEvent")] |
| |
| /** |
| * Dispatched before a child of a legend is removed. |
| * |
| * <p>This event is delivered when any of the following methods is called: |
| * <code>removeChild()</code>, <code>removeChildAt()</code>, |
| * or <code>removeAllChildren()</code>.</p> |
| * |
| * @eventType mx.events.ChildExistenceChangedEvent.CHILD_REMOVE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="childRemove", type="mx.events.ChildExistenceChangedEvent")] |
| |
| /** |
| * Dispatched when the <code>data</code> property changes. |
| * |
| * <p>When a legend is used as a renderer in a List or other components, |
| * the <code>data</code> property is used pass to the legend |
| * the data to display.</p> |
| * |
| * @eventType mx.events.FlexEvent.DATA_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="dataChange", type="mx.events.FlexEvent")] |
| |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| include "../styles/metadata/BorderStyles.as" |
| include "../styles/metadata/PaddingStyles.as" |
| include "../styles/metadata/TextStyles.as" |
| include "../styles/metadata/GapStyles.as" |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| /** |
| * Accent color used by component skins. The default button skin uses this color |
| * to tint the background. Slider track highlighting uses this color. |
| * |
| * @default #0099FF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="accentColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * If a background image is specified, this style specifies |
| * whether it is fixed with regard to the viewport (<code>"fixed"</code>) |
| * or scrolls along with the content (<code>"scroll"</code>). |
| * |
| * @default "scroll" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="backgroundAttachment", type="String", inherit="no")] |
| |
| /** |
| * Alpha level of the color defined by the <code>backgroundColor</code> |
| * property, of the image or SWF file defined by the <code>backgroundImage</code> |
| * style. |
| * Valid values range from 0.0 to 1.0. For most controls, the default value is 1.0, |
| * but for ToolTip controls, the default value is 0.95 and for Alert controls, the default value is 0.9. |
| * |
| * @default 1.0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="backgroundAlpha", type="Number", inherit="no", theme="halo, spark")] |
| |
| /** |
| * Background color of a component. |
| * You can have both a <code>backgroundColor</code> and a |
| * <code>backgroundImage</code> set. |
| * Some components do not have a background. |
| * The DataGrid control ignores this style. |
| * The default value is <code>undefined</code>, which means it is not set. |
| * If both this style and the <code>backgroundImage</code> style |
| * are <code>undefined</code>, the component has a transparent background. |
| * |
| * <p>For the Application container, this style specifies the background color |
| * while the application loads, and a background gradient while it is running. |
| * Flex calculates the gradient pattern between a color slightly darker than |
| * the specified color, and a color slightly lighter than the specified color.</p> |
| * |
| * <p>The default skins of most Flex controls are partially transparent. As a result, the background color of |
| * a container partially "bleeds through" to controls that are in that container. You can avoid this by setting the |
| * alpha values of the control's <code>fillAlphas</code> property to 1, as the following example shows: |
| * <pre> |
| * <mx:<i>Container</i> backgroundColor="0x66CC66"/> |
| * <mx:<i>ControlName</i> ... fillAlphas="[1,1]"/> |
| * </mx:<i>Container</i>></pre> |
| * </p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="backgroundColor", type="uint", format="Color", inherit="no", theme="halo, spark")] |
| |
| /** |
| * Determines the color of a ProgressBar. |
| * A ProgressBar is filled with a vertical gradient between this color |
| * and a brighter color computed from it. |
| * This style has no effect on other components, but can be set on a container |
| * to control the appearance of all progress bars found within. |
| * The default value is <code>undefined</code>, which means it is not set. |
| * In this case, the <code>themeColor</code> style property is used. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="barColor", type="uint", format="Color", inherit="yes", theme="halo")] |
| |
| /** |
| * The alpha of the content background for this component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="contentBackgroundAlpha", type="Number", inherit="yes", theme="spark")] |
| |
| /** |
| * Color of the content area of the component. |
| * |
| * @default 0xFFFFFF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="contentBackgroundColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * Radius of component corners. |
| * The default value depends on the component class; |
| * if not overridden for the class, the default value |
| * is 0. |
| * The default value for ApplicationControlBar is 5. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="cornerRadius", type="Number", format="Length", inherit="no", theme="halo, spark")] |
| |
| /** |
| * The alpha value for the overlay that is placed on top of the |
| * container when it is disabled. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="disabledOverlayAlpha", type="Number", inherit="no")] |
| |
| /** |
| * Color of focus ring when the component is in focus |
| * |
| * @default 0x70B2EE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="focusColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * Horizontal alignment of each child inside its tile cell. |
| * Possible values are <code>"left"</code>, <code>"center"</code>, and |
| * <code>"right"</code>. |
| * If the value is <code>"left"</code>, the left edge of each child |
| * is at the left edge of its cell. |
| * If the value is <code>"center"</code>, each child is centered horizontally |
| * within its cell. |
| * If the value is <code>"right"</code>, the right edge of each child |
| * is at the right edge of its cell. |
| * |
| * @default "left" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="horizontalAlign", type="String", enumeration="left,center,right", inherit="no")] |
| |
| /** |
| * Specifies the label placement of the legend element. |
| * Valid values are <code>"top"</code>, <code>"bottom"</code>, |
| * <code>"right"</code>, and <code>"left"</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="labelPlacement", type="String", enumeration="top,bottom,right,left", inherit="yes")] |
| |
| /** |
| * Specifies the height of the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="markerHeight", type="Number", format="Length", inherit="yes")] |
| |
| /** |
| * Specifies the width of the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="markerWidth", type="Number", format="Length", inherit="yes")] |
| |
| /** |
| * Number of pixels between the legend's bottom border |
| * and the bottom of its content area. |
| * |
| * @default 0 |
| * |
| * @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 legend's top border |
| * and the top of its content area. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="paddingTop", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * Color of any symbol of a component. Examples include the check mark of a CheckBox or |
| * the arrow of a ScrollBar button. |
| * |
| * @default 0x000000 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * Specifies the line stroke for the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="stroke", type="Object", inherit="no")] |
| |
| /** |
| * Vertical alignment of each child inside its tile cell. |
| * Possible values are <code>"top"</code>, <code>"middle"</code>, and |
| * <code>"bottom"</code>. |
| * If the value is <code>"top"</code>, the top edge of each child |
| * is at the top edge of its cell. |
| * If the value is <code>"middle"</code>, each child is centered vertically |
| * within its cell. |
| * If the value is <code>"bottom"</code>, the bottom edge of each child |
| * is at the bottom edge of its cell. |
| * |
| * @default "top" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="verticalAlign", type="String", enumeration="bottom,middle,top", inherit="no")] |
| |
| [ResourceBundle("core")] |
| |
| //-------------------------------------- |
| // Excluded APIs |
| //-------------------------------------- |
| [Exclude(name="defaultButton", kind="property")] |
| [Exclude(name="horizontalScrollPolicy", kind="property")] |
| [Exclude(name="icon", kind="property")] |
| [Exclude(name="label", kind="property")] |
| [Exclude(name="tileHeight", kind="property")] |
| [Exclude(name="tileWidth", kind="property")] |
| [Exclude(name="verticalScrollPolicy", kind="property")] |
| |
| [Exclude(name="focusIn", kind="event")] |
| [Exclude(name="focusOut", kind="event")] |
| |
| [Exclude(name="focusBlendMode", kind="style")] |
| [Exclude(name="focusSkin", kind="style")] |
| [Exclude(name="focusThickness", kind="style")] |
| |
| [Exclude(name="focusInEffect", kind="effect")] |
| [Exclude(name="focusOutEffect", kind="effect")] |
| |
| |
| //-------------------------------------- |
| // Other metadata |
| //-------------------------------------- |
| |
| [DefaultBindingProperty(destination="dataProvider")] |
| |
| [DefaultTriggerEvent("itemClick")] |
| |
| [IconFile("Legend.png")] |
| |
| /** |
| * The Legend control adds a legend to your charts, |
| * where the legend displays the label for each data series in the chart |
| * and a key showing the chart element for the series. |
| * |
| * <p>You can initialize a Legend control by binding a chart control |
| * identifier to the Legend control's <code>dataProvider</code> property, |
| * or you can define an Array of LegendItem objects.</p> |
| * |
| * @mxml |
| * |
| * <p>The <code><mx:Legend></code> tag inherits all the properties |
| * of its parent classes and adds the following properties:</p> |
| * |
| * <pre> |
| * <mx:Legend |
| * <strong>Properties</strong> |
| * autoLayout="true|false" |
| * clipContent="true|false" |
| * creationIndex="undefined" |
| * creationPolicy="auto|all|queued|none" |
| * dataProvider="<i>No default</i>" |
| * direction="horizontal|vertical" |
| * horizontalScrollPosition="0" |
| * legendItemClass="<i>No default</i>" |
| * verticalScrollPosition="0" |
| * |
| * <strong>Styles</strong> |
| * backgroundAlpha="1.0" |
| * backgroundAttachment="scroll" |
| * backgroundColor="undefined" |
| * backgroundDisabledColor="undefined" |
| * backgroundImage="undefined" |
| * backgroundSize="auto" |
| * barColor="undefined" |
| * borderColor="0xAAB3B3" |
| * borderSides="left top right bottom" |
| * borderSkin="mx.skins.halo.HaloBorder" |
| * borderStyle="inset|none|solid|outset" |
| * borderThickness="1" |
| * color="0x0B333C" |
| * cornerRadius="0" |
| * disabledColor="0xAAB3B3" |
| * disbledOverlayAlpha="undefined" |
| * dropShadowColor="0x000000" |
| * dropShadowEnabled="false" |
| * fontAntiAliasType="advanced" |
| * fontfamily="Verdana" |
| * fontGridFitType="pixel" |
| * fontSharpness="0"" |
| * fontSize="10" |
| * fontStyle="normal" |
| * fontThickness="0" |
| * fontWeight="normal" |
| * horizontalAlign="left|center|right" |
| * horizontalGap="<i>8</i>" |
| * labelPlacement="right|left|top|bottom" |
| * markerHeight="15" |
| * markerWidth="10" |
| * paddingBottom="0" |
| * paddingLeft="0" |
| * paddingRight="0" |
| * paddingTop="0" |
| * shadowDirection="center" |
| * shadowDistance="2" |
| * stroke="<i>IStroke; no default</i>" |
| * textAlign="left" |
| * textDecoration="none|underline" |
| * textIndent="0" |
| * verticalAlign="top|middle|bottom" |
| * verticalGap="<i>6</i>" |
| * |
| * <strong>Events</strong> |
| * childAdd="<i>No default</i>" |
| * childIndexChange="<i>No default</i>" |
| * childRemove="<i>No default</i>" |
| * dataChange="<i>No default</i>" |
| * itemClick="<i>Event; no default</i>" |
| * itemMouseDown="<i>Event; no default</i>" |
| * itemMouseOut="<i>Event; no default</i>" |
| * itemMouseOver="<i>Event; no default</i>" |
| * itemMouseUp="<i>Event; no default</i>" |
| * /> |
| * </pre> |
| * |
| * @see mx.charts.LegendItem |
| * |
| * @includeExample examples/PlotChartExample.mxml |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| |
| public class Legend extends UIComponent implements IContainer |
| |
| { |
| include "../core/Version.as" |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Notes: Child management |
| // |
| //-------------------------------------------------------------------------- |
| |
| /* |
| |
| Although at the level of a Flash DisplayObjectContainer, all |
| children are equal, in a Flex Container some children are "more |
| equal than others". (George Orwell, "Animal Farm") |
| |
| In particular, Flex distinguishes between content children and |
| non-content (or "chrome") children. Content children are the kind |
| that can be specified in MXML. If you put several controls |
| into a VBox, those are its content children. Non-content children |
| are the other ones that you get automatically, such as a |
| background/border, scrollbars, the titlebar of a Panel, |
| AccordionHeaders, etc. |
| |
| Most application developers are uninterested in non-content children, |
| so Container overrides APIs such as numChildren and getChildAt() |
| to deal only with content children. For example, Container, keeps |
| its own _numChildren counter. |
| |
| Container assumes that content children are contiguous, and that |
| non-content children come before or after the content children. |
| In order words, Container partitions DisplayObjectContainer's |
| index range into three parts: |
| |
| A B C D E F G H I |
| 0 1 2 3 4 5 6 7 8 <- index for all children |
| 0 1 2 3 <- index for content children |
| |
| The content partition contains the content children D E F G. |
| The pre-content partition contains the non-content children |
| A B C that always stay before the content children. |
| The post-content partition contains the non-content children |
| H I that always stay after the content children. |
| |
| Container maintains two state variables, _firstChildIndex |
| and _numChildren, which keep track of the partitioning. |
| In this example, _firstChildIndex would be 3 and _numChildren |
| would be 4. |
| |
| */ |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class constants |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * See changedStyles, below |
| */ |
| private static const MULTIPLE_PROPERTIES:String = "<MULTIPLE>"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| mx_internal function getLayoutChildAt(index:int):IUIComponent |
| { |
| return PostScaleAdapter.getCompatibleIUIComponent(getChildAt(index)); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function Legend() |
| { |
| super(); |
| |
| tabEnabled = false; |
| tabFocusEnabled = false; |
| |
| showInAutomationHierarchy = false; |
| |
| // If available, get soft-link to the RichEditableText class |
| // to use in keyDownHandler(). |
| if (ApplicationDomain.currentDomain.hasDefinition( |
| "spark.components.RichEditableText")) |
| { |
| richEditableTextClass = |
| Class(ApplicationDomain.currentDomain.getDefinition( |
| "spark.components.RichEditableText")); |
| } |
| |
| direction = "vertical"; |
| |
| addEventListener(MouseEvent.CLICK, childMouseEventHandler); |
| addEventListener(MouseEvent.MOUSE_OVER, childMouseEventHandler); |
| addEventListener(MouseEvent.MOUSE_OUT, childMouseEventHandler); |
| addEventListener(MouseEvent.MOUSE_UP, childMouseEventHandler); |
| addEventListener(MouseEvent.MOUSE_DOWN, childMouseEventHandler); |
| |
| _dataProvider = new ArrayCollection(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // Child creation vars |
| //---------------------------------- |
| |
| /** |
| * The creation policy of this container. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var actualCreationPolicy:String; |
| |
| /** |
| * @private |
| */ |
| private var numChildrenBefore:int; |
| |
| /** |
| * @private |
| */ |
| public var recursionFlag:Boolean = true; |
| |
| //---------------------------------- |
| // Layout vars |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Remember when a child has been added or removed. |
| * When that occurs, we want to run the LayoutManager |
| * (even if autoLayout is false). |
| */ |
| private var forceLayout:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| mx_internal var doingLayout:Boolean = false; |
| |
| //---------------------------------- |
| // Style vars |
| //---------------------------------- |
| |
| /** |
| * @private |
| * If this value is non-null, then we need to recursively notify children |
| * that a style property has changed. If one style property has changed, |
| * this field holds the name of the style that changed. If multiple style |
| * properties have changed, then the value of this field is |
| * Container.MULTIPLE_PROPERTIES. |
| */ |
| private var changedStyles:String = null; |
| |
| //---------------------------------- |
| // Scrolling vars |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _creatingContentPane:Boolean = false; |
| |
| /** |
| * Containers use an internal content pane to control scrolling. |
| * The <code>creatingContentPane</code> is <code>true</code> while the container is creating |
| * the content pane so that some events can be ignored or blocked. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get creatingContentPane():Boolean |
| { |
| return _creatingContentPane; |
| } |
| public function set creatingContentPane(value:Boolean):void |
| { |
| _creatingContentPane = value; |
| } |
| |
| /** |
| * @private |
| * A box that takes up space in the lower right corner, |
| * between the horizontal and vertical scrollbars. |
| */ |
| protected var whiteBox:Shape; |
| |
| /** |
| * @private |
| */ |
| mx_internal var contentPane:Sprite = null; |
| |
| /** |
| * @private |
| * Flags that remember what work to do during the next updateDisplayList(). |
| */ |
| private var scrollPositionChanged:Boolean = true; |
| private var horizontalScrollPositionPending:Number; |
| private var verticalScrollPositionPending:Number; |
| |
| /** |
| * @private |
| * Cached values describing the total size of the content being scrolled |
| * and the size of the area in which the scrolled content is displayed. |
| */ |
| private var scrollableWidth:Number = 0; |
| private var scrollableHeight:Number = 0; |
| private var viewableWidth:Number = 0; |
| private var viewableHeight:Number = 0; |
| |
| //---------------------------------- |
| // Other vars |
| //---------------------------------- |
| |
| /** |
| * @private |
| * The border/background object. |
| */ |
| mx_internal var border:IFlexDisplayObject; |
| |
| /** |
| * @private |
| * Sprite used to block user input when the container is disabled. |
| */ |
| mx_internal var blocker:Sprite; |
| |
| /** |
| * @private |
| * Keeps track of the number of mouse events we are listening for |
| */ |
| private var mouseEventReferenceCount:int = 0; |
| |
| /** |
| * @private |
| * Soft-link to RichEditableText class object, if available. |
| */ |
| private var richEditableTextClass:Class; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Cached value from findCellSize() call in measure(), |
| * so that updateDisplayList() doesn't also have to call findCellSize(). |
| */ |
| mx_internal var cellWidth:Number; |
| |
| /** |
| * @private |
| * Cached value from findCellSize() call in measure(), |
| * so that updateDisplaylist() doesn't also have to call findCellSize(). |
| */ |
| mx_internal var cellHeight:Number; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // direction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the direction property. |
| */ |
| private var _direction:String = "horizontal"; |
| |
| [Bindable("directionChanged")] |
| [Inspectable(category="General", enumeration="vertical,horizontal", defaultValue="horizontal")] |
| |
| /** |
| * Determines how children are placed in the container. |
| * Possible MXML values are <code>"horizontal"</code> and |
| * <code>"vertical"</code>. |
| * In ActionScript, you can set the direction using the values |
| * TileDirection.HORIZONTAL or TileDirection.VERTICAL. |
| * The default value is <code>"horizontal"</code>. |
| * (If the container is a Legend container, which is a subclass of Tile, |
| * the default value is <code>"vertical"</code>.) |
| * |
| * <p>The first child is always placed at the upper-left of the |
| * Tile container. |
| * If the <code>direction</code> is <code>"horizontal"</code>, |
| * the children are placed left-to-right in the topmost row, |
| * and then left-to-right in the second row, and so on. |
| * If the value is <code>"vertical"</code>, the children are placed |
| * top-to-bottom in the leftmost column, and then top-to-bottom |
| * in the second column, and so on.</p> |
| * |
| * @default "horizontal" |
| * |
| * @see TileDirection |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get direction():String |
| { |
| return _direction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set direction(value:String):void |
| { |
| _direction = value; |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("directionChanged")); |
| } |
| |
| //---------------------------------- |
| // tileHeight |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the tileHeight property. |
| */ |
| private var _tileHeight:Number; |
| |
| [Bindable("resize")] |
| [Inspectable(category="General")] |
| |
| /** |
| * Height of each tile cell, in pixels. |
| * If this property is <code>NaN</code>, the default, the height |
| * of each cell is determined by the height of the tallest child. |
| * If you set this property, the specified value overrides |
| * this calculation. |
| * |
| * @default NaN |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get tileHeight():Number |
| { |
| return _tileHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set tileHeight(value:Number):void |
| { |
| _tileHeight = value; |
| |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // tileWidth |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the tileWidth property. |
| */ |
| private var _tileWidth:Number; |
| |
| [Bindable("resize")] |
| [Inspectable(category="General")] |
| |
| /** |
| * Width of each tile cell, in pixels. |
| * If this property is <code>NaN</code>, the defualt, the width |
| * of each cell is determined by the width of the widest child. |
| * If you set this property, the specified value overrides |
| * this calculation. |
| * |
| * @default NaN |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get tileWidth():Number |
| { |
| return _tileWidth; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set tileWidth(value:Number):void |
| { |
| _tileWidth = value; |
| |
| invalidateSize(); |
| } |
| |
| /** |
| * @private |
| */ |
| private var _preferredMajorAxisLength:Number; |
| |
| /** |
| * @private |
| */ |
| private var _actualMajorAxisLength:Number; |
| |
| /** |
| * @private |
| */ |
| private var _childrenDirty:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var _unscaledWidth:Number; |
| |
| /** |
| * @private |
| */ |
| private var _unscaledHeight:Number; |
| |
| /** |
| * @private |
| */ |
| private static var legendItemLinkage:LegendItem = null; |
| |
| /** |
| * @private |
| */ |
| private var _dataProviderChanged:Boolean = false; |
| |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // baselinePosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| * The baselinePosition of a Container is calculated |
| * as if there was a UITextField using the Container's styles |
| * whose top is at viewMetrics.top. |
| */ |
| override public function get baselinePosition():Number |
| { |
| if (!validateBaselinePosition()) |
| return NaN; |
| |
| // Unless the height is very small, the baselinePosition |
| // of a generic Container is calculated as if there was |
| // a UITextField using the Container's styles |
| // whose top is at viewMetrics.top. |
| // If the height is small, the baselinePosition is calculated |
| // as if there were text within whose ascent the Container |
| // is vertically centered. |
| // At the crossover height, these two calculations |
| // produce the same result. |
| |
| var lineMetrics:TextLineMetrics = measureText("Wj"); |
| |
| if (height < 2 * viewMetrics.top + 4 + lineMetrics.ascent) |
| return int(height + (lineMetrics.ascent - height) / 2); |
| |
| return viewMetrics.top + 2 + lineMetrics.ascent; |
| } |
| |
| //---------------------------------- |
| // contentMouseX |
| //---------------------------------- |
| |
| /** |
| * @copy mx.core.UIComponent#contentMouseX |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function get contentMouseX():Number |
| { |
| if (contentPane) |
| return contentPane.mouseX; |
| |
| return super.contentMouseX; |
| } |
| |
| //---------------------------------- |
| // contentMouseY |
| //---------------------------------- |
| |
| /** |
| * @copy mx.core.UIComponent#contentMouseY |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function get contentMouseY():Number |
| { |
| if (contentPane) |
| return contentPane.mouseY; |
| |
| return super.contentMouseY; |
| } |
| |
| //---------------------------------- |
| // doubleClickEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Propagate to children. |
| */ |
| override public function set doubleClickEnabled(value:Boolean):void |
| { |
| super.doubleClickEnabled = value; |
| |
| if (contentPane) |
| { |
| var n:int = contentPane.numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:InteractiveObject = |
| contentPane.getChildAt(i) as InteractiveObject; |
| if (child) |
| child.doubleClickEnabled = value; |
| } |
| } |
| } |
| |
| //---------------------------------- |
| // enabled |
| //---------------------------------- |
| |
| [Inspectable(category="General", enumeration="true,false", defaultValue="true")] |
| |
| /** |
| * @private |
| */ |
| override public function set enabled(value:Boolean):void |
| { |
| super.enabled = value; |
| |
| invalidateProperties(); |
| |
| if (border && border is IInvalidating) |
| IInvalidating(border).invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // focusPane |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the focusPane property. |
| */ |
| private var _focusPane:Sprite; |
| |
| /** |
| * @private |
| * Focus pane associated with this object. |
| * An object has a focus pane when one of its children has got focus. |
| */ |
| override public function get focusPane():Sprite |
| { |
| return _focusPane; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set focusPane(o:Sprite):void |
| { |
| // The addition or removal of the focus sprite should not trigger |
| // a measurement/layout pass. Temporarily set the invalidation flags, |
| // so that calls to invalidateSize() and invalidateDisplayList() have |
| // no effect. |
| var oldInvalidateSizeFlag:Boolean = invalidateSizeFlag; |
| var oldInvalidateDisplayListFlag:Boolean = invalidateDisplayListFlag; |
| invalidateSizeFlag = true; |
| invalidateDisplayListFlag = true; |
| |
| if (o) |
| { |
| rawChildren.addChild(o); |
| |
| o.x = 0; |
| o.y = 0; |
| o.scrollRect = null; |
| |
| _focusPane = o; |
| } |
| else |
| { |
| rawChildren.removeChild(_focusPane); |
| |
| _focusPane = null; |
| } |
| |
| if (o && contentPane) |
| { |
| o.x = contentPane.x; |
| o.y = contentPane.y; |
| o.scrollRect = contentPane.scrollRect; |
| } |
| |
| invalidateSizeFlag = oldInvalidateSizeFlag; |
| invalidateDisplayListFlag = oldInvalidateDisplayListFlag; |
| } |
| |
| //---------------------------------- |
| // moduleFactory |
| //---------------------------------- |
| /** |
| * @private |
| */ |
| override public function set moduleFactory(moduleFactory:IFlexModuleFactory):void |
| { |
| super.moduleFactory = moduleFactory; |
| |
| // Register the _creationPolicy style as inheriting. See the creationPolicy |
| // getter for details on usage of this style. |
| styleManager.registerInheritingStyle("_creationPolicy"); |
| } |
| |
| //---------------------------------- |
| // $numChildren |
| //---------------------------------- |
| |
| /** |
| * @private |
| * This property allows access to the Player's native implementation |
| * of the numChildren property, which can be useful since components |
| * can override numChildren and thereby hide the native implementation. |
| * Note that this "base property" is final and cannot be overridden, |
| * so you can count on it to reflect what is happening at the player level. |
| */ |
| mx_internal final function get $numChildren():int |
| { |
| return super.numChildren; |
| } |
| |
| //---------------------------------- |
| // numChildren |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the numChildren property. |
| */ |
| mx_internal var _numChildren:int = 0; |
| |
| /** |
| * Number of child components in this container. |
| * |
| * <p>The number of children is initially equal |
| * to the number of children declared in MXML. |
| * At runtime, new children may be added by calling |
| * <code>addChild()</code> or <code>addChildAt()</code>, |
| * and existing children may be removed by calling |
| * <code>removeChild()</code>, <code>removeChildAt()</code>, |
| * or <code>removeAllChildren()</code>.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function get numChildren():int |
| { |
| return contentPane ? contentPane.numChildren : _numChildren; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // dataProvider |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the dataProvider property. |
| */ |
| private var _dataProvider:Object; |
| |
| [Bindable("collectionChange")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * Set of data to be used in the Legend. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get dataProvider():Object |
| { |
| return _dataProvider; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataProvider( |
| value:Object /* String, ViewStack or Array */):void |
| { |
| if (_dataProvider is ChartBase) |
| { |
| _dataProvider.removeEventListener("legendDataChanged", |
| legendDataChangedHandler); |
| } |
| |
| _dataProvider = value ? value : []; |
| |
| if (_dataProvider is ChartBase) |
| { |
| // weak listeners to collections and dataproviders |
| _dataProvider.addEventListener("legendDataChanged", |
| legendDataChangedHandler, false, 0, true); |
| } |
| else if (_dataProvider is ICollectionView) |
| { |
| } |
| else if (_dataProvider is IList) |
| { |
| _dataProvider = new ListCollectionView(IList(_dataProvider)); |
| } |
| else if (_dataProvider is Array) |
| { |
| _dataProvider = new ArrayCollection(_dataProvider as Array); |
| } |
| else if (_dataProvider != null) |
| { |
| _dataProvider = new ArrayCollection([_dataProvider]); |
| } |
| else |
| { |
| _dataProvider = new ArrayCollection(); |
| } |
| |
| invalidateProperties(); |
| invalidateSize(); |
| _childrenDirty = true; |
| |
| dispatchEvent(new Event("collectionChange")); |
| } |
| |
| //---------------------------------- |
| // legendItemClass |
| //---------------------------------- |
| |
| /** |
| * The class used to instantiate LegendItem objects. |
| * When a legend's content is derived from the chart or data, |
| * it instantiates one instance of <code>legendItemClass</code> |
| * for each item described by the <code>dataProvider</code>. |
| * If you want custom behavior in your legend items, |
| * you can assign a subclass of LegendItem to this property |
| * to have the Legend create instances of their derived type instead. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var legendItemClass:Class = LegendItem; |
| |
| //---------------------------------- |
| // autoLayout |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the autoLayout property. |
| */ |
| private var _autoLayout:Boolean = true; |
| |
| [Inspectable(defaultValue="true")] |
| |
| /** |
| * If <code>true</code>, measurement and layout are done |
| * when the position or size of a child is changed. |
| * If <code>false</code>, measurement and layout are done only once, |
| * when children are added to or removed from the container. |
| * |
| * <p>When using the Move effect, the layout around the component that |
| * is moving does not readjust to fit that the Move effect animates. |
| * Setting a container's <code>autoLayout</code> property to |
| * <code>true</code> has no effect on this behavior.</p> |
| * |
| * <p>The Zoom effect does not work when the <code>autoLayout</code> |
| * property is <code>false</code>.</p> |
| * |
| * <p>The <code>autoLayout</code> property does not apply to |
| * Accordion or ViewStack containers.</p> |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get autoLayout():Boolean |
| { |
| return _autoLayout; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set autoLayout(value:Boolean):void |
| { |
| _autoLayout = value; |
| |
| // If layout is being turned back on, trigger a layout to occur now. |
| if (value) |
| { |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| var p:IInvalidating = parent as IInvalidating; |
| if (p) |
| { |
| p.invalidateSize(); |
| p.invalidateDisplayList(); |
| } |
| } |
| } |
| |
| //---------------------------------- |
| // borderMetrics |
| //---------------------------------- |
| |
| /** |
| * Returns an EdgeMetrics object that has four properties: |
| * <code>left</code>, <code>top</code>, <code>right</code>, |
| * and <code>bottom</code>. |
| * The value of each property is equal to the thickness of one side |
| * of the border, expressed in pixels. |
| * |
| * <p>Unlike <code>viewMetrics</code>, this property is not |
| * overridden by subclasses of Container.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get borderMetrics():EdgeMetrics |
| { |
| return border && border is IRectangularBorder ? |
| IRectangularBorder(border).borderMetrics : |
| EdgeMetrics.EMPTY; |
| } |
| |
| //---------------------------------- |
| // childDescriptors |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the childDescriptors property. |
| * This variable is initialized in the construct() method |
| * using the childDescriptors in the initObj, which is autogenerated. |
| * If this Container was not created by createComponentFromDescriptor(), |
| * its childDescriptors property is null. |
| */ |
| private var _childDescriptors:Array /* of UIComponentDescriptor */; |
| |
| /** |
| * Array of UIComponentDescriptor objects produced by the MXML compiler. |
| * |
| * <p>Each UIComponentDescriptor object contains the information |
| * specified in one child MXML tag of the container's MXML tag. |
| * The order of the UIComponentDescriptor objects in the Array |
| * is the same as the order of the child tags. |
| * During initialization, the child descriptors are used to create |
| * the container's child UIComponent objects and its Repeater objects, |
| * and to give them the initial property values, event handlers, effects, |
| * and so on, that were specified in MXML.</p> |
| * |
| * @see mx.core.UIComponentDescriptor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get childDescriptors():Array /* of UIComponentDescriptor */ |
| { |
| return _childDescriptors; |
| } |
| |
| public function set childDescriptors(value:Array):void /* of UIComponentDescriptor */ |
| { |
| _childDescriptors = value; |
| } |
| |
| //---------------------------------- |
| // childRepeaters |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the childRepeaters property. |
| */ |
| private var _childRepeaters:Array; |
| |
| /** |
| * @private |
| * An array of the Repeater objects found within this container. |
| */ |
| mx_internal function get childRepeaters():Array |
| { |
| return _childRepeaters; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function set childRepeaters(value:Array):void |
| { |
| _childRepeaters = value; |
| } |
| |
| //---------------------------------- |
| // clipContent |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the clipContent property. |
| */ |
| private var _clipContent:Boolean = true; |
| |
| [Inspectable(defaultValue="true")] |
| |
| /** |
| * Whether to apply a clip mask if the positions and/or sizes |
| * of this container's children extend outside the borders of |
| * this container. |
| * If <code>false</code>, the children of this container |
| * remain visible when they are moved or sized outside the |
| * borders of this container. |
| * If <code>true</code>, the children of this container are clipped. |
| * |
| * <p>If <code>clipContent</code> is <code>false</code>, then scrolling |
| * is disabled for this container and scrollbars will not appear. |
| * If <code>clipContent</code> is true, then scrollbars will usually |
| * appear when the container's children extend outside the border of |
| * the container. |
| * For additional control over the appearance of scrollbars, |
| * see <code>horizontalScrollPolicy</code> and <code>verticalScrollPolicy</code>.</p> |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get clipContent():Boolean |
| { |
| return _clipContent; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set clipContent(value:Boolean):void |
| { |
| if (_clipContent != value) |
| { |
| _clipContent = value; |
| |
| invalidateDisplayList(); |
| } |
| } |
| |
| //---------------------------------- |
| // createdComponents |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Internal variable used to keep track of the components created |
| * by this Container. This is different than the list maintained |
| * by DisplayObjectContainer, because it includes Repeaters. |
| */ |
| private var _createdComponents:Array; |
| |
| /** |
| * @private |
| * An array of all components created by this container including |
| * Repeater components. |
| */ |
| mx_internal function get createdComponents():Array |
| { |
| return _createdComponents; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function set createdComponents(value:Array):void |
| { |
| _createdComponents = value; |
| } |
| |
| //---------------------------------- |
| // creationIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the creationIndex property. |
| */ |
| private var _creationIndex:int = -1; |
| |
| [Inspectable(defaultValue="undefined")] |
| |
| /** |
| * Specifies the order to instantiate and draw the children |
| * of the container. |
| * |
| * <p>This property can only be used when the <code>creationPolicy</code> |
| * property is set to <code>ContainerCreationPolicy.QUEUED</code>. |
| * Otherwise, it is ignored.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Deprecated] |
| public function get creationIndex():int |
| { |
| return _creationIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set creationIndex(value:int):void |
| { |
| _creationIndex = value; |
| } |
| |
| //---------------------------------- |
| // creationPolicy |
| //---------------------------------- |
| |
| // Internal flag used when creationPolicy="none". |
| // When set, the value of the backing store _creationPolicy |
| // style is "auto" so descendants inherit the correct value. |
| private var creationPolicyNone:Boolean = false; |
| |
| [Inspectable(enumeration="all,auto,none")] |
| |
| /** |
| * The child creation policy for this MX Container. |
| * ActionScript values can be <code>ContainerCreationPolicy.AUTO</code>, |
| * <code>ContainerCreationPolicy.ALL</code>, |
| * or <code>ContainerCreationPolicy.NONE</code>. |
| * MXML values can be <code>auto</code>, <code>all</code>, |
| * or <code>none</code>. |
| * |
| * <p>If no <code>creationPolicy</code> is specified for a container, |
| * that container inherits its parent's <code>creationPolicy</code>. |
| * If no <code>creationPolicy</code> is specified for the Application, |
| * it defaults to <code>ContainerCreationPolicy.AUTO</code>.</p> |
| * |
| * <p>A <code>creationPolicy</code> of <code>ContainerCreationPolicy.AUTO</code> means |
| * that the container delays creating some or all descendants |
| * until they are needed, a process which is known as <i>deferred |
| * instantiation</i>. |
| * This policy produces the best startup time because fewer |
| * UIComponents are created initially. |
| * However, this introduces navigation delays when a user navigates |
| * to other parts of the application for the first time. |
| * Navigator containers such as Accordion, TabNavigator, and ViewStack |
| * implement the <code>ContainerCreationPolicy.AUTO</code> policy by creating all their |
| * children immediately, but wait to create the deeper descendants |
| * of a child until it becomes the selected child of the navigator |
| * container.</p> |
| * |
| * <p>A <code>creationPolicy</code> of <code>ContainerCreationPolicy.ALL</code> means |
| * that the navigator containers immediately create deeper descendants |
| * for each child, rather than waiting until that child is |
| * selected. For single-view containers such as a VBox container, |
| * there is no difference between the <code>ContainerCreationPolicy.AUTO</code> and |
| * <code>ContainerCreationPolicy.ALL</code> policies.</p> |
| * |
| * <p>A <code>creationPolicy</code> of <code>ContainerCreationPolicy.NONE</code> means |
| * that the container creates none of its children. |
| * In that case, it is the responsibility of the MXML author |
| * to create the children by calling the |
| * <code>createComponentsFromDescriptors()</code> method.</p> |
| * |
| * @default ContainerCreationPolicy.AUTO |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get creationPolicy():String |
| { |
| // Use an inheriting style as the backing storage for this property. |
| // This allows the property to be inherited by either mx or spark |
| // containers, and also to correctly cascade through containers that |
| // don't have this property (ie Group). |
| // This style is an implementation detail and should be considered |
| // private. Do not set it from CSS. |
| if (creationPolicyNone) |
| return ContainerCreationPolicy.NONE; |
| return getStyle("_creationPolicy"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set creationPolicy(value:String):void |
| { |
| var styleValue:String = value; |
| |
| if (value == ContainerCreationPolicy.NONE) |
| { |
| // creationPolicy of none is not inherited by descendants. |
| // In this case, set the style to "auto" and set a local |
| // flag for subsequent access to the creationPolicy property. |
| creationPolicyNone = true; |
| styleValue = ContainerCreationPolicy.AUTO; |
| } |
| else |
| { |
| creationPolicyNone = false; |
| } |
| |
| setStyle("_creationPolicy", styleValue); |
| |
| setActualCreationPolicies(value); |
| } |
| |
| //---------------------------------- |
| // defaultButton |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the defaultButton property. |
| */ |
| private var _defaultButton:IFlexDisplayObject; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The Button control designated as the default button |
| * for the container. |
| * When controls in the container have focus, pressing the |
| * Enter key is the same as clicking this Button control. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get defaultButton():IFlexDisplayObject |
| { |
| return _defaultButton; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set defaultButton(value:IFlexDisplayObject):void |
| { |
| _defaultButton = value; |
| ContainerGlobals.focusedContainer = null; |
| } |
| |
| //---------------------------------- |
| // deferredContentCreated |
| //---------------------------------- |
| |
| /** |
| * IDeferredContentOwner equivalent of processedDescriptors |
| * |
| * @see UIComponent#processedDescriptors |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get deferredContentCreated():Boolean |
| { |
| return processedDescriptors; |
| } |
| |
| //---------------------------------- |
| // data |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the data property. |
| */ |
| private var _data:Object; |
| |
| [Bindable("dataChange")] |
| [Inspectable(environment="none")] |
| |
| /** |
| * The <code>data</code> property lets you pass a value |
| * to the component when you use it in an item renderer or item editor. |
| * You typically use data binding to bind a field of the <code>data</code> |
| * property to a property of this component. |
| * |
| * <p>You do not set this property in MXML.</p> |
| * |
| * @default null |
| * @see mx.core.IDataRenderer |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get data():Object |
| { |
| return _data; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set data(value:Object):void |
| { |
| _data = value; |
| |
| dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); |
| |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // firstChildIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the firstChildIndex property. |
| */ |
| private var _firstChildIndex:int = 0; |
| |
| /** |
| * @private |
| * The index of the first content child, |
| * when dealing with both content and non-content children. |
| */ |
| mx_internal function get firstChildIndex():int |
| { |
| return _firstChildIndex; |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the horizontalScrollPosition property. |
| */ |
| private var _horizontalScrollPosition:Number = 0; |
| |
| [Bindable("scroll")] |
| [Bindable("viewChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The current position of the horizontal scroll bar. |
| * This is equal to the distance in pixels between the left edge |
| * of the scrollable surface and the leftmost piece of the surface |
| * that is currently visible. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get horizontalScrollPosition():Number |
| { |
| if (!isNaN(horizontalScrollPositionPending)) |
| return horizontalScrollPositionPending; |
| return _horizontalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set horizontalScrollPosition(value:Number):void |
| { |
| if (_horizontalScrollPosition == value) |
| return; |
| |
| // Note: We can't use maxHorizontalScrollPosition to clamp the value here. |
| // The horizontalScrollBar may not exist yet, |
| // or its maxPos might change during layout. |
| // (For example, you could set the horizontalScrollPosition of a childless container, |
| // then add a child which causes it to have a scrollbar.) |
| // The horizontalScrollPosition gets clamped to the range 0 through maxHorizontalScrollPosition |
| // late, in the updateDisplayList() method, just before the scrollPosition |
| // of the horizontalScrollBar is set. |
| |
| _horizontalScrollPosition = value; |
| scrollPositionChanged = true; |
| if (!initialized) |
| horizontalScrollPositionPending = value; |
| |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("viewChanged")); |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPolicy |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the horizontalScrollPolicy property. |
| */ |
| mx_internal var _horizontalScrollPolicy:String = ScrollPolicy.AUTO; |
| |
| [Bindable("horizontalScrollPolicyChanged")] |
| [Inspectable(category="General", enumeration="off,on,auto", defaultValue="auto")] |
| |
| /** |
| * Specifies whether the horizontal scroll bar is always present, |
| * always absent, or automatically added when needed. |
| * ActionScript values can be <code>ScrollPolicy.ON</code>, <code>ScrollPolicy.OFF</code>, |
| * and <code>ScrollPolicy.AUTO</code>. |
| * MXML values can be <code>"on"</code>, <code>"off"</code>, |
| * and <code>"auto"</code>. |
| * |
| * <p>Setting this property to <code>ScrollPolicy.OFF</code> also prevents the |
| * <code>horizontalScrollPosition</code> property from having an effect.</p> |
| * |
| * <p>Note: This property does not apply to the ControlBar container.</p> |
| * |
| * <p>If the <code>horizontalScrollPolicy</code> is <code>ScrollPolicy.AUTO</code>, |
| * the horizontal scroll bar appears when all of the following |
| * are true:</p> |
| * <ul> |
| * <li>One of the container's children extends beyond the left |
| * edge or right edge of the container.</li> |
| * <li>The <code>clipContent</code> property is <code>true</code>.</li> |
| * <li>The width and height of the container are large enough to |
| * reasonably accommodate a scroll bar.</li> |
| * </ul> |
| * |
| * @default ScrollPolicy.AUTO |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get horizontalScrollPolicy():String |
| { |
| return ScrollPolicy.OFF; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set horizontalScrollPolicy(value:String):void |
| { |
| } |
| |
| //---------------------------------- |
| // icon |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the icon property. |
| */ |
| private var _icon:Class = null; |
| |
| [Bindable("iconChanged")] |
| [Inspectable(category="General", defaultValue="", format="EmbeddedFile")] |
| |
| /** |
| * The Class of the icon displayed by some navigator |
| * containers to represent this Container. |
| * |
| * <p>For example, if this Container is a child of a TabNavigator, |
| * this icon appears in the corresponding tab. |
| * If this Container is a child of an Accordion, |
| * this icon appears in the corresponding header.</p> |
| * |
| * <p>To embed the icon in the SWF file, use the @Embed() |
| * MXML compiler directive:</p> |
| * |
| * <pre> |
| * icon="@Embed('filepath')" |
| * </pre> |
| * |
| * <p>The image can be a JPEG, GIF, PNG, SVG, or SWF file.</p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get icon():Class |
| { |
| return _icon; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set icon(value:Class):void |
| { |
| _icon = value; |
| |
| dispatchEvent(new Event("iconChanged")); |
| } |
| |
| //---------------------------------- |
| // label |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the label property. |
| */ |
| private var _label:String = ""; |
| |
| [Bindable("labelChanged")] |
| [Inspectable(category="General", defaultValue="")] |
| |
| /** |
| * The text displayed by some navigator containers to represent |
| * this Container. |
| * |
| * <p>For example, if this Container is a child of a TabNavigator, |
| * this string appears in the corresponding tab. |
| * If this Container is a child of an Accordion, |
| * this string appears in the corresponding header.</p> |
| * |
| * @default "" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get label():String |
| { |
| return _label; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set label(value:String):void |
| { |
| _label = value; |
| |
| dispatchEvent(new Event("labelChanged")); |
| } |
| |
| //---------------------------------- |
| // maxHorizontalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * The largest possible value for the |
| * <code>horizontalScrollPosition</code> property. |
| * Defaults to 0 if the horizontal scrollbar is not present. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get maxHorizontalScrollPosition():Number |
| { |
| return Math.max(scrollableWidth - viewableWidth, 0); |
| } |
| |
| //---------------------------------- |
| // maxVerticalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * The largest possible value for the |
| * <code>verticalScrollPosition</code> property. |
| * Defaults to 0 if the vertical scrollbar is not present. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get maxVerticalScrollPosition():Number |
| { |
| return Math.max(scrollableHeight - viewableHeight, 0); |
| } |
| |
| //---------------------------------- |
| // numChildrenCreated |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _numChildrenCreated:int = -1; |
| |
| /** |
| * @private |
| * The number of children created inside this container. |
| * The default value is 0. |
| */ |
| mx_internal function get numChildrenCreated():int |
| { |
| return _numChildrenCreated; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function set numChildrenCreated(value:int):void |
| { |
| _numChildrenCreated = value; |
| } |
| |
| //---------------------------------- |
| // numRepeaters |
| //---------------------------------- |
| |
| /** |
| * @private |
| * The number of Repeaters in this Container. |
| * |
| * <p>This number includes Repeaters that are immediate children of this |
| * container and Repeaters that are nested inside other Repeaters. |
| * Consider the following example:</p> |
| * |
| * <pre> |
| * <mx:HBox> |
| * <mx:Repeater dataProvider="[1, 2]"> |
| * <mx:Repeater dataProvider="..."> |
| * <mx:Button/> |
| * </mx:Repeater> |
| * </mx:Repeater> |
| * <mx:HBox> |
| * </pre> |
| * |
| * <p>In this example, the <code>numRepeaters</code> property |
| * for the HBox would be set equal to 3 -- one outer Repeater |
| * and two inner repeaters.</p> |
| * |
| * <p>The <code>numRepeaters</code> property does not include Repeaters |
| * that are nested inside other containers. |
| * Consider this example:</p> |
| * |
| * <pre> |
| * <mx:HBox> |
| * <mx:Repeater dataProvider="[1, 2]"> |
| * <mx:VBox> |
| * <mx:Repeater dataProvider="..."> |
| * <mx:Button/> |
| * </mx:Repeater> |
| * </mx:VBox> |
| * </mx:Repeater> |
| * <mx:HBox> |
| * </pre> |
| * |
| * <p>In this example, the <code>numRepeaters</code> property |
| * for the outer HBox would be set equal to 1 -- just the outer repeater. |
| * The two inner VBox containers would also have a |
| * <code>numRepeaters</code> property equal to 1 -- one Repeater |
| * per VBox.</p> |
| */ |
| mx_internal function get numRepeaters():int |
| { |
| return childRepeaters ? childRepeaters.length : 0; |
| } |
| |
| //---------------------------------- |
| // rawChildren |
| //---------------------------------- |
| |
| /** |
| * @private |
| * The single IChildList object that's always returned |
| * from the rawChildren property, below. |
| */ |
| private var _rawChildren:LegendRawChildrenList; |
| |
| /** |
| * A container typically contains child components, which can be enumerated |
| * using the <code>Container.getChildAt()</code> method and |
| * <code>Container.numChildren</code> property. In addition, the container |
| * may contain style elements and skins, such as the border and background. |
| * Flash Player and AIR do not draw any distinction between child components |
| * and skins. They are all accessible using the player's |
| * <code>getChildAt()</code> method and |
| * <code>numChildren</code> property. |
| * However, the Container class overrides the <code>getChildAt()</code> method |
| * and <code>numChildren</code> property (and several other methods) |
| * to create the illusion that |
| * the container's children are the only child components. |
| * |
| * <p>If you need to access all of the children of the container (both the |
| * content children and the skins), then use the methods and properties |
| * on the <code>rawChildren</code> property instead of the regular Container methods. |
| * For example, use the <code>Container.rawChildren.getChildAt())</code> method. |
| * However, if a container creates a ContentPane Sprite object for its children, |
| * the <code>rawChildren</code> property value only counts the ContentPane, not the |
| * container's children. |
| * It is not always possible to determine when a container will have a ContentPane.</p> |
| * |
| * <p><b>Note:</b>If you call the <code>addChild</code> or |
| * <code>addChildAt</code> method of the <code>rawChildren</code> object, |
| * set <code>tabFocusEnabled = false</code> on the component that you have added. |
| * Doing so prevents users from tabbing to the visual-only component |
| * that you have added.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get rawChildren():IChildList |
| { |
| if (!_rawChildren) |
| _rawChildren = new LegendRawChildrenList(this); |
| |
| return _rawChildren; |
| } |
| |
| //---------------------------------- |
| // usePadding |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| mx_internal function get usePadding():Boolean |
| { |
| // Containers, by default, always use padding. |
| return true; |
| } |
| |
| //---------------------------------- |
| // verticalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the verticalScrollPosition property. |
| */ |
| private var _verticalScrollPosition:Number = 0; |
| |
| [Bindable("scroll")] |
| [Bindable("viewChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The current position of the vertical scroll bar. |
| * This is equal to the distance in pixels between the top edge |
| * of the scrollable surface and the topmost piece of the surface |
| * that is currently visible. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get verticalScrollPosition():Number |
| { |
| if (!isNaN(verticalScrollPositionPending)) |
| return verticalScrollPositionPending; |
| |
| return _verticalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set verticalScrollPosition(value:Number):void |
| { |
| if (_verticalScrollPosition == value) |
| return; |
| |
| // Note: We can't use maxVerticalScrollPosition to clamp the value here. |
| // The verticalScrollBar may not exist yet, |
| // or its maxPos might change during layout. |
| // (For example, you could set the verticalScrollPosition of a childless container, |
| // then add a child which causes it to have a scrollbar.) |
| // The verticalScrollPosition gets clamped to the range 0 through maxVerticalScrollPosition |
| // late, in the updateDisplayList() method, just before the scrollPosition |
| // of the verticalScrollBar is set. |
| |
| _verticalScrollPosition = value; |
| scrollPositionChanged = true; |
| if (!initialized) |
| verticalScrollPositionPending = value; |
| |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("viewChanged")); |
| } |
| |
| //---------------------------------- |
| // verticalScrollPolicy |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the verticalScrollPolicy property. |
| */ |
| mx_internal var _verticalScrollPolicy:String = ScrollPolicy.AUTO; |
| |
| [Bindable("verticalScrollPolicyChanged")] |
| [Inspectable(category="General", enumeration="off,on,auto", defaultValue="auto")] |
| |
| /** |
| * Specifies whether the vertical scroll bar is always present, |
| * always absent, or automatically added when needed. |
| * Possible values are <code>ScrollPolicy.ON</code>, <code>ScrollPolicy.OFF</code>, |
| * and <code>ScrollPolicy.AUTO</code>. |
| * MXML values can be <code>"on"</code>, <code>"off"</code>, |
| * and <code>"auto"</code>. |
| * |
| * <p>Setting this property to <code>ScrollPolicy.OFF</code> also prevents the |
| * <code>verticalScrollPosition</code> property from having an effect.</p> |
| * |
| * <p>Note: This property does not apply to the ControlBar container.</p> |
| * |
| * <p>If the <code>verticalScrollPolicy</code> is <code>ScrollPolicy.AUTO</code>, |
| * the vertical scroll bar appears when all of the following |
| * are true:</p> |
| * <ul> |
| * <li>One of the container's children extends beyond the top |
| * edge or bottom edge of the container.</li> |
| * <li>The <code>clipContent</code> property is <code>true</code>.</li> |
| * <li>The width and height of the container are large enough to |
| * reasonably accommodate a scroll bar.</li> |
| * </ul> |
| * |
| * @default ScrollPolicy.AUTO |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get verticalScrollPolicy():String |
| { |
| return ScrollPolicy.OFF; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set verticalScrollPolicy(value:String):void |
| { |
| } |
| |
| //---------------------------------- |
| // viewMetrics |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Offsets including borders and scrollbars |
| */ |
| private var _viewMetrics:EdgeMetrics; |
| |
| /** |
| * Returns an object that has four properties: <code>left</code>, |
| * <code>top</code>, <code>right</code>, and <code>bottom</code>. |
| * The value of each property equals the thickness of the chrome |
| * (visual elements) around the edge of the container. |
| * |
| * <p>The chrome includes the border thickness. |
| * If the <code>horizontalScrollPolicy</code> or <code>verticalScrollPolicy</code> |
| * property value is <code>ScrollPolicy.ON</code>, the |
| * chrome also includes the thickness of the corresponding |
| * scroll bar. If a scroll policy is <code>ScrollPolicy.AUTO</code>, |
| * the chrome measurement does not include the scroll bar thickness, |
| * even if a scroll bar is displayed.</p> |
| * |
| * <p>Subclasses of Container should override this method, so that |
| * they include other chrome to be taken into account when positioning |
| * the Container's children. |
| * For example, the <code>viewMetrics</code> property for the |
| * Panel class should return an object whose <code>top</code> property |
| * includes the thickness of the Panel container's title bar.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get viewMetrics():EdgeMetrics |
| { |
| var bm:EdgeMetrics = borderMetrics; |
| |
| // If scrollPolicy is ScrollPolicy.ON, then the scrollbars are accounted for |
| // during both measurement and layout. |
| // |
| // If scrollPolicy is ScrollPolicy.AUTO, then scrollbars are ignored during |
| // measurement. Otherwise, the entire layout of the app could change |
| // everytime that the scrollbars turn on or off. |
| // |
| // However, we do take the width of scrollbars into account when laying |
| // out our children. That way, children that have a percentage width or |
| // percentage height will only expand to consume space that's left over |
| // after leaving room for the scrollbars. |
| var verticalScrollBarIncluded:Boolean = false; |
| /*verticalScrollBar != null && |
| (doingLayout || verticalScrollPolicy == ScrollPolicy.ON);*/ |
| var horizontalScrollBarIncluded:Boolean = false; |
| /*horizontalScrollBar != null && |
| (doingLayout || horizontalScrollPolicy == ScrollPolicy.ON);*/ |
| if (!verticalScrollBarIncluded && !horizontalScrollBarIncluded) |
| return bm; |
| |
| // The viewMetrics property needs to return its own object. |
| // Rather than allocating a new one each time, we'll allocate one once |
| // and then hold a reference to it. |
| if (!_viewMetrics) |
| { |
| _viewMetrics = bm.clone(); |
| } |
| else |
| { |
| _viewMetrics.left = bm.left; |
| _viewMetrics.right = bm.right; |
| _viewMetrics.top = bm.top; |
| _viewMetrics.bottom = bm.bottom; |
| } |
| |
| if (verticalScrollBarIncluded) |
| _viewMetrics.right;// += verticalScrollBar.minWidth; |
| if (horizontalScrollBarIncluded) |
| _viewMetrics.bottom;// += horizontalScrollBar.minHeight; |
| |
| return _viewMetrics; |
| } |
| |
| //---------------------------------- |
| // viewMetricsAndPadding |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Cached value containing the view metrics plus the object's margins. |
| */ |
| private var _viewMetricsAndPadding:EdgeMetrics; |
| |
| /** |
| * Returns an object that has four properties: <code>left</code>, |
| * <code>top</code>, <code>right</code>, and <code>bottom</code>. |
| * The value of each property is equal to the thickness of the chrome |
| * (visual elements) |
| * around the edge of the container plus the thickness of the object's margins. |
| * |
| * <p>The chrome includes the border thickness. |
| * If the <code>horizontalScrollPolicy</code> or <code>verticalScrollPolicy</code> |
| * property value is <code>ScrollPolicy.ON</code>, the |
| * chrome also includes the thickness of the corresponding |
| * scroll bar. If a scroll policy is <code>ScrollPolicy.AUTO</code>, |
| * the chrome measurement does not include the scroll bar thickness, |
| * even if a scroll bar is displayed.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get viewMetricsAndPadding():EdgeMetrics |
| { |
| // If this object has scrollbars, and if the verticalScrollPolicy |
| // is not ScrollPolicy.ON, then the view metrics change |
| // depending on whether we're doing layout or not. |
| // In that case, we can't use a cached value. |
| // In all other cases, use the cached value if it exists. |
| if (_viewMetricsAndPadding && |
| (horizontalScrollPolicy == ScrollPolicy.ON) && |
| (verticalScrollPolicy == ScrollPolicy.ON)) |
| { |
| return _viewMetricsAndPadding; |
| } |
| |
| if (!_viewMetricsAndPadding) |
| _viewMetricsAndPadding = new EdgeMetrics(); |
| |
| var o:EdgeMetrics = _viewMetricsAndPadding; |
| var vm:EdgeMetrics = viewMetrics; |
| |
| o.left = vm.left + getStyle("paddingLeft"); |
| o.right = vm.right + getStyle("paddingRight"); |
| o.top = vm.top + getStyle("paddingTop"); |
| o.bottom = vm.bottom + getStyle("paddingBottom"); |
| |
| return o; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: EventDispatcher |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * If we add a mouse event, then we need to add a mouse shield |
| * to us and to all our children |
| * The mouseShield style is a non-inheriting style |
| * that is used by the view. |
| * The mouseShieldChildren style is an inherting style |
| * that is used by the children views. |
| */ |
| override public function addEventListener( |
| type:String, listener:Function, |
| useCapture:Boolean = false, |
| priority:int = 0, |
| useWeakReference:Boolean = false):void |
| { |
| super.addEventListener(type, listener, useCapture, |
| priority, useWeakReference); |
| |
| // If we are a mouse event, then create a mouse shield. |
| if (type == MouseEvent.CLICK || |
| type == MouseEvent.DOUBLE_CLICK || |
| type == MouseEvent.MOUSE_DOWN || |
| type == MouseEvent.MOUSE_MOVE || |
| type == MouseEvent.MOUSE_OVER || |
| type == MouseEvent.MOUSE_OUT || |
| type == MouseEvent.MOUSE_UP || |
| type == MouseEvent.MOUSE_WHEEL) |
| { |
| if (mouseEventReferenceCount < 0x7FFFFFFF /* int_max */ && |
| mouseEventReferenceCount++ == 0) |
| { |
| setStyle("mouseShield", true); |
| setStyle("mouseShieldChildren", true); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| * We're doing special behavior on addEventListener to make sure that |
| * we successfully capture mouse events, even when there's no background. |
| * However, this means adding an event listener changes the behavior |
| * a little, and this can be troublesome for overlapping components |
| * that now don't get any mouse events. This is acceptable normally; |
| * however, automation adds certain events to the Container, and |
| * it'd be better if automation support didn't modify the behavior of |
| * the component. For this reason, especially, we have an mx_internal |
| * $addEventListener to add event listeners without affecting the behavior |
| * of the component. |
| */ |
| mx_internal function $addEventListener( |
| type:String, listener:Function, |
| useCapture:Boolean = false, |
| priority:int = 0, |
| useWeakReference:Boolean = false):void |
| { |
| super.addEventListener(type, listener, useCapture, |
| priority, useWeakReference); |
| } |
| |
| /** |
| * @private |
| * Remove the mouse shield if we no longer listen to any mouse events |
| */ |
| |
| override public function removeEventListener( |
| type:String, listener:Function, |
| useCapture:Boolean = false):void |
| { |
| super.removeEventListener(type, listener, useCapture); |
| |
| // If we are a mouse event, |
| // then decrement the mouse shield reference count. |
| if (type == MouseEvent.CLICK || |
| type == MouseEvent.DOUBLE_CLICK || |
| type == MouseEvent.MOUSE_DOWN || |
| type == MouseEvent.MOUSE_MOVE || |
| type == MouseEvent.MOUSE_OVER || |
| type == MouseEvent.MOUSE_OUT || |
| type == MouseEvent.MOUSE_UP || |
| type == MouseEvent.MOUSE_WHEEL) |
| { |
| if (mouseEventReferenceCount > 0 && |
| --mouseEventReferenceCount == 0) |
| { |
| setStyle("mouseShield", false); |
| setStyle("mouseShieldChildren", false); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| * We're doing special behavior on removeEventListener to make sure that |
| * we successfully capture mouse events, even when there's no background. |
| * However, this means removing an event listener changes the behavior |
| * a little, and this can be troublesome for overlapping components |
| * that now don't get any mouse events. This is acceptable normally; |
| * however, automation adds certain events to the Container, and |
| * it'd be better if automation support didn't modify the behavior of |
| * the component. For this reason, especially, we have an mx_internal |
| * $removeEventListener to remove event listeners without affecting the behavior |
| * of the component. |
| */ |
| mx_internal function $removeEventListener( |
| type:String, listener:Function, |
| useCapture:Boolean = false):void |
| { |
| super.removeEventListener(type, listener, useCapture); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: DisplayObjectContainer |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Adds a child DisplayObject to this Container. |
| * The child is added after other existing children, |
| * so that the first child added has index 0, |
| * the next has index 1, an so on. |
| * |
| * <p><b>Note: </b>While the <code>child</code> argument to the method |
| * is specified as of type DisplayObject, the argument must implement |
| * the IUIComponent interface to be added as a child of a container. |
| * All Flex components implement this interface.</p> |
| * |
| * <p>Children are layered from back to front. |
| * In other words, if children overlap, the one with index 0 |
| * is farthest to the back, and the one with index |
| * <code>numChildren - 1</code> is frontmost. |
| * This means the newly added children are layered |
| * in front of existing children.</p> |
| * |
| * @param child The DisplayObject to add as a child of this Container. |
| * It must implement the IUIComponent interface. |
| * |
| * @return The added child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of the added component. |
| * |
| * @see mx.core.IUIComponent |
| * |
| * @tiptext Adds a child object to this container. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function addChild(child:DisplayObject):DisplayObject |
| { |
| return addChildAt(child, numChildren); |
| |
| /* Application and Panel are depending on addChild calling addChildAt */ |
| |
| /* |
| addingChild(child); |
| |
| if (contentPane) |
| contentPane.addChild(child); |
| else |
| $addChild(child); |
| |
| childAdded(child); |
| |
| return child; |
| */ |
| } |
| |
| /** |
| * Adds a child DisplayObject to this Container. |
| * The child is added at the index specified. |
| * |
| * <p><b>Note: </b>While the <code>child</code> argument to the method |
| * is specified as of type DisplayObject, the argument must implement |
| * the IUIComponent interface to be added as a child of a container. |
| * All Flex components implement this interface.</p> |
| * |
| * <p>Children are layered from back to front. |
| * In other words, if children overlap, the one with index 0 |
| * is farthest to the back, and the one with index |
| * <code>numChildren - 1</code> is frontmost. |
| * This means the newly added children are layered |
| * in front of existing children.</p> |
| * |
| * <p>When you add a new child at an index that is already occupied |
| * by an old child, it doesn't replace the old child; instead the |
| * old child and the ones after it "slide over" and have their index |
| * incremented by one. |
| * For example, suppose a Container contains the children |
| * (A, B, C) and you add D at index 1. |
| * Then the container will contain (A, D, B, C). |
| * If you want to replace an old child, you must first remove it |
| * before adding the new one.</p> |
| * |
| * @param child The DisplayObject to add as a child of this Container. |
| * It must implement the IUIComponent interface. |
| * |
| * @param index The index to add the child at. |
| * |
| * @return The added child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of the added component. |
| * |
| * @see mx.core.IUIComponent |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function addChildAt(child:DisplayObject, |
| index:int):DisplayObject |
| { |
| var formerParent:DisplayObjectContainer = child.parent; |
| if (formerParent && !(formerParent is Loader)) |
| { |
| // Adjust index if necessary when former parent happens |
| // to be the same container. |
| if (formerParent == this) |
| index = (index == numChildren) ? index - 1 : index; |
| |
| formerParent.removeChild(child); |
| } |
| |
| addingChild(child); |
| |
| // Add the child to either this container or its contentPane. |
| // The player will dispatch an "added" event from the child |
| // after it has been added, so all "added" handlers execute here. |
| if (contentPane) |
| contentPane.addChildAt(child, index); |
| else |
| $addChildAt(child, _firstChildIndex + index); |
| |
| childAdded(child); |
| |
| if ((child is UIComponent) && UIComponent(child).isDocument) |
| BindingManager.setEnabled(child, true); |
| |
| return child; |
| } |
| |
| /** |
| * Removes a child DisplayObject from the child list of this Container. |
| * The removed child will have its <code>parent</code> |
| * property set to null. |
| * The child will still exist unless explicitly destroyed. |
| * If you add it to another container, |
| * it will retain its last known state. |
| * |
| * @param child The DisplayObject to remove. |
| * |
| * @return The removed child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of the removed component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function removeChild(child:DisplayObject):DisplayObject |
| { |
| if (child is IDeferredInstantiationUIComponent && |
| IDeferredInstantiationUIComponent(child).descriptor) |
| { |
| // if child's descriptor is present, it means child was created |
| // with MXML. Need to go through and remove component in |
| // createdComponents so there is no memory leak by keeping |
| // a reference to the removed child (SDK-12506) |
| |
| if (createdComponents) |
| { |
| var n:int = createdComponents.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| if (createdComponents[i] === child) |
| { |
| // delete this reference |
| createdComponents.splice(i, 1); |
| } |
| } |
| } |
| } |
| |
| removingChild(child); |
| |
| if ((child is UIComponent) && UIComponent(child).isDocument) |
| BindingManager.setEnabled(child, false); |
| |
| // Remove the child from either this container or its contentPane. |
| // The player will dispatch a "removed" event from the child |
| // before it is removed, so all "removed" handlers execute here. |
| if (contentPane) |
| contentPane.removeChild(child); |
| else |
| $removeChild(child); |
| |
| childRemoved(child); |
| |
| return child; |
| } |
| |
| /** |
| * Removes a child DisplayObject from the child list of this Container |
| * at the specified index. |
| * The removed child will have its <code>parent</code> |
| * property set to null. |
| * The child will still exist unless explicitly destroyed. |
| * If you add it to another container, |
| * it will retain its last known state. |
| * |
| * @param index The child index of the DisplayObject to remove. |
| * |
| * @return The removed child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of the removed component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function removeChildAt(index:int):DisplayObject |
| { |
| return removeChild(getChildAt(index)); |
| |
| /* |
| |
| Shouldn't implement removeChildAt() in terms of removeChild(). |
| If we change this ViewStack IList, Application, and Panel are depending on it |
| |
| */ |
| } |
| |
| /** |
| * Gets the <i>n</i>th child component object. |
| * |
| * <p>The children returned from this method include children that are |
| * declared in MXML and children that are added using the |
| * <code>addChild()</code> or <code>addChildAt()</code> method.</p> |
| * |
| * @param childIndex Number from 0 to (numChildren - 1). |
| * |
| * @return Reference to the child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of a specific Flex control, such as ComboBox or TextArea. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function getChildAt(index:int):DisplayObject |
| { |
| if (contentPane) |
| { |
| return contentPane.getChildAt(index); |
| } |
| else |
| { |
| // The DisplayObjectContainer implementation of getChildAt() |
| // in the Player throws this error if the index is bad, |
| // so we should too. |
| // if (index < 0 || index >= _numChildren) |
| // throw new RangeError("The supplied index is out of bounds"); |
| |
| return super.getChildAt(_firstChildIndex + index); |
| } |
| } |
| |
| /** |
| * Returns the child whose <code>name</code> property is the specified String. |
| * |
| * @param name The identifier of the child. |
| * |
| * @return The DisplayObject representing the child as an object of type DisplayObject. |
| * You typically cast the return value to UIComponent, |
| * or to the type of a specific Flex control, such as ComboBox or TextArea. |
| * Throws a run-time error if the child of the specified name does not exist. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function getChildByName(name:String):DisplayObject |
| { |
| if (contentPane) |
| { |
| return contentPane.getChildByName(name); |
| } |
| else |
| { |
| var child:DisplayObject = super.getChildByName(name); |
| if (!child) |
| return null; |
| |
| // Check if the child is in the index range for content children. |
| var index:int = super.getChildIndex(child) - _firstChildIndex; |
| if (index < 0 || index >= _numChildren) |
| return null; |
| |
| return child; |
| } |
| } |
| |
| /** |
| * Gets the zero-based index of a specific child. |
| * |
| * <p>The first child of the container (i.e.: the first child tag |
| * that appears in the MXML declaration) has an index of 0, |
| * the second child has an index of 1, and so on. |
| * The indexes of a container's children determine |
| * the order in which they get laid out. |
| * For example, in a VBox the child with index 0 is at the top, |
| * the child with index 1 is below it, etc.</p> |
| * |
| * <p>If you add a child by calling the <code>addChild()</code> method, |
| * the new child's index is equal to the largest index among existing |
| * children plus one. |
| * You can insert a child at a specified index by using the |
| * <code>addChildAt()</code> method; in that case the indices of the |
| * child previously at that index, and the children at higher indices, |
| * all have their index increased by 1 so that all indices fall in the |
| * range from 0 to <code>(numChildren - 1)</code>.</p> |
| * |
| * <p>If you remove a child by calling <code>removeChild()</code> |
| * or <code>removeChildAt()</code> method, then the indices of the |
| * remaining children are adjusted so that all indices fall in the |
| * range from 0 to <code>(numChildren - 1)</code>.</p> |
| * |
| * <p>If <code>myView.getChildIndex(myChild)</code> returns 5, |
| * then <code>myView.getChildAt(5)</code> returns myChild.</p> |
| * |
| * <p>The index of a child may be changed by calling the |
| * <code>setChildIndex()</code> method.</p> |
| * |
| * @param child Reference to child whose index to get. |
| * |
| * @return Number between 0 and (numChildren - 1). |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function getChildIndex(child:DisplayObject):int |
| { |
| if (contentPane) |
| { |
| return contentPane.getChildIndex(child); |
| } |
| else |
| { |
| var index:int = super.getChildIndex(child) - _firstChildIndex; |
| |
| // The DisplayObjectContainer implementation of getChildIndex() |
| // in the Player throws this error if the child isn't a child, |
| // so we should too. |
| // if (index < 0 || index >= _numChildren) |
| // throw new ArgumentError("The DisplayObject supplied must be a child of the caller."); |
| |
| return index; |
| } |
| } |
| |
| /** |
| * Sets the index of a particular child. |
| * See the <code>getChildIndex()</code> method for a |
| * description of the child's index. |
| * |
| * @param child Reference to child whose index to set. |
| * |
| * @param newIndex Number that indicates the new index. |
| * Must be an integer between 0 and (numChildren - 1). |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function setChildIndex(child:DisplayObject, newIndex:int):void |
| { |
| var oldIndex:int; |
| |
| var eventOldIndex:int = oldIndex; |
| var eventNewIndex:int = newIndex; |
| |
| if (contentPane) |
| { |
| contentPane.setChildIndex(child, newIndex); |
| |
| if (_autoLayout || forceLayout) |
| invalidateDisplayList(); |
| } |
| else |
| { |
| oldIndex = super.getChildIndex(child); |
| |
| // Offset the index, to leave room for skins before the list of children |
| newIndex += _firstChildIndex; |
| |
| if (newIndex == oldIndex) |
| return; |
| |
| // Change the child's index, shifting around other children to make room |
| super.setChildIndex(child, newIndex); |
| |
| invalidateDisplayList(); |
| |
| eventOldIndex = oldIndex - _firstChildIndex; |
| eventNewIndex = newIndex - _firstChildIndex; |
| } |
| |
| // Notify others that the child index has changed |
| var event:IndexChangedEvent = new IndexChangedEvent(IndexChangedEvent.CHILD_INDEX_CHANGE); |
| event.relatedObject = child; |
| event.oldIndex = eventOldIndex; |
| event.newIndex = eventNewIndex; |
| dispatchEvent(event); |
| |
| dispatchEvent(new Event("childrenChanged")); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function contains(child:DisplayObject):Boolean |
| { |
| if (contentPane) |
| return contentPane.contains(child); |
| else |
| return super.contains(child); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: IVisualElementContainer |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#numElements |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get numElements():int |
| { |
| return numChildren; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#getElementAt() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getElementAt(index:int):IVisualElement |
| { |
| return getChildAt(index) as IVisualElement; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#getElementIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getElementIndex(element:IVisualElement):int |
| { |
| if (! (element is DisplayObject) ) |
| throw ArgumentError(element + " is not found in this Container"); |
| |
| return getChildIndex(element as DisplayObject); |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#addElement() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function addElement(element:IVisualElement):IVisualElement |
| { |
| if (! (element is DisplayObject) ) |
| throw ArgumentError(element + " is not supported in this Container"); |
| |
| return addChild(element as DisplayObject) as IVisualElement; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#addElementAt() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function addElementAt(element:IVisualElement, index:int):IVisualElement |
| { |
| if (! (element is DisplayObject) ) |
| throw ArgumentError(element + " is not supported in this Container"); |
| |
| return addChildAt(element as DisplayObject, index) as IVisualElement; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#removeElement() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function removeElement(element:IVisualElement):IVisualElement |
| { |
| if (! (element is DisplayObject) ) |
| throw ArgumentError(element + " is not found in this Container"); |
| |
| return removeChild(element as DisplayObject) as IVisualElement; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#removeElementAt() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function removeElementAt(index:int):IVisualElement |
| { |
| return removeChildAt(index) as IVisualElement; |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#removeAllElements() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function removeAllElements():void |
| { |
| for (var i:int = numElements - 1; i >= 0; i--) |
| { |
| removeElementAt(i); |
| } |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#setElementIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function setElementIndex(element:IVisualElement, index:int):void |
| { |
| if (! (element is DisplayObject) ) |
| throw ArgumentError(element + " is not found in this Container"); |
| |
| return setChildIndex(element as DisplayObject, index); |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#swapElements() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function swapElements(element1:IVisualElement, element2:IVisualElement):void |
| { |
| if (! (element1 is DisplayObject) ) |
| throw ArgumentError(element1 + " is not found in this Container"); |
| if (! (element2 is DisplayObject) ) |
| throw ArgumentError(element2 + " is not found in this Container"); |
| |
| swapChildren(element1 as DisplayObject, element2 as DisplayObject); |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#swapElementsAt() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function swapElementsAt(index1:int, index2:int):void |
| { |
| swapChildrenAt(index1, index2); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function initialize():void |
| { |
| // Until component templating is implemented, the childDescriptors |
| // come either from the top-level descriptor in the component itself |
| // (i.e., the defined children) or from a descriptor for an instance |
| // of that component in some other component or app (i.e., the |
| // instance children). At this point _childDescriptors already |
| // contains the instance children if there are any; but if the |
| // document defines any children, we have to use them instead. |
| |
| if (documentDescriptor && !processedDescriptors) |
| { |
| // NOTE: documentDescriptor.properties is a potentially |
| // expensive function call, so do it only once. |
| var props:* = documentDescriptor.properties; |
| if (props && props.childDescriptors) |
| { |
| if (_childDescriptors) |
| { |
| var message:String = resourceManager.getString( |
| "core", "multipleChildSets_ClassAndInstance"); |
| throw new Error(message); |
| } |
| else |
| { |
| _childDescriptors = props.childDescriptors; |
| } |
| } |
| } |
| |
| super.initialize(); |
| } |
| |
| /** |
| * @private |
| * Create components that are children of this Container. |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| // Create the border/background object. |
| createBorder(); |
| |
| // Determine the child-creation policy (ContainerCreationPolicy.AUTO, |
| // ContainerCreationPolicy.ALL, or ContainerCreationPolicy.NONE). |
| // If the author has specified a policy, use it. |
| // Otherwise, use the parent's policy. |
| // This must be set before createChildren() gets called. |
| if (actualCreationPolicy == null) |
| { |
| if (creationPolicy != null) |
| actualCreationPolicy = creationPolicy; |
| |
| if (actualCreationPolicy == ContainerCreationPolicy.QUEUED) |
| actualCreationPolicy = ContainerCreationPolicy.AUTO; |
| } |
| |
| // It is ok for actualCreationPolicy to be null. Popups require it. |
| |
| if (actualCreationPolicy == ContainerCreationPolicy.NONE) |
| { |
| actualCreationPolicy = ContainerCreationPolicy.AUTO; |
| } |
| else if (actualCreationPolicy == ContainerCreationPolicy.QUEUED) |
| { |
| var mainApp:* = parentApplication ? |
| parentApplication : |
| FlexGlobals.topLevelApplication; |
| |
| if ("addToCreationQueue" in mainApp) |
| mainApp.addToCreationQueue(this, _creationIndex, null, this); |
| else // If the app doesn't support queued creation, create our components now |
| createComponentsFromDescriptors(); |
| } |
| else if (recursionFlag) |
| { |
| // Create whatever children are appropriate. If any were |
| // previously created, they don't get re-created. |
| createComponentsFromDescriptors(); |
| } |
| |
| // If autoLayout is initially false, we still want to do |
| // measurement once (even if we don't have any children) |
| if (autoLayout == false) |
| forceLayout = true; |
| |
| // weak references |
| UIComponentGlobals.layoutManager.addEventListener( |
| FlexEvent.UPDATE_COMPLETE, layoutCompleteHandler, false, 0, true); |
| } |
| |
| /** |
| * @private |
| * Override to NOT set precessedDescriptors. |
| */ |
| override protected function initializationComplete():void |
| { |
| // Don't call super.initializationComplete(). |
| } |
| |
| /** |
| * @private |
| */ |
| override public function invalidateLayoutDirection():void |
| { |
| super.invalidateLayoutDirection(); |
| |
| // We have to deal with non-styled raw children here. |
| if (_rawChildren) |
| { |
| const rawNumChildren:int = _rawChildren.numChildren; |
| |
| for (var i:int = 0; i < rawNumChildren; i++) |
| { |
| var child:DisplayObject = _rawChildren.getChildAt(i); |
| if (!(child is IStyleClient) && child is ILayoutDirectionElement) |
| ILayoutDirectionElement(child).invalidateLayoutDirection(); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitProperties():void |
| { |
| super.commitProperties(); |
| |
| if (changedStyles) |
| { |
| // If multiple properties have changed, set styleProp to null. |
| // Otherwise, set it to the name of the style that has changed. |
| var styleProp:String = changedStyles == MULTIPLE_PROPERTIES ? |
| null : |
| changedStyles; |
| |
| super.notifyStyleChangeInChildren(styleProp, true); |
| |
| changedStyles = null; |
| } |
| |
| createOrDestroyBlocker(); |
| |
| if (_childrenDirty) |
| { |
| populateFromArray(_dataProvider); |
| _childrenDirty = false; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function validateSize(recursive:Boolean = false):void |
| { |
| // If autoLayout is turned off and we haven't recently created |
| // or destroyed any children, then we're not doing any |
| // measurement or layout. |
| // Return false indicating that the measurements haven't changed. |
| if (autoLayout == false && forceLayout == false) |
| { |
| if (recursive) |
| { |
| var n:int = super.numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:DisplayObject = super.getChildAt(i); |
| if (child is ILayoutManagerClient ) |
| ILayoutManagerClient (child).validateSize(true); |
| } |
| } |
| adjustSizesForScaleChanges(); |
| } |
| else |
| { |
| super.validateSize(recursive); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function validateDisplayList():void |
| { |
| // trace(">>Container validateLayoutPhase " + this); |
| |
| var vm:EdgeMetrics; |
| |
| // If autoLayout is turned off and we haven't recently created or |
| // destroyed any children, then don't do any layout |
| if (_autoLayout || forceLayout) |
| { |
| doingLayout = true; |
| super.validateDisplayList(); |
| doingLayout = false; |
| } |
| else |
| { |
| // Layout borders, Panel headers, and other border chrome. |
| layoutChrome(unscaledWidth, unscaledHeight); |
| } |
| |
| // Set this to block requeuing when sizing children. |
| invalidateDisplayListFlag = true; |
| |
| // Based on the positions of the children, determine |
| // whether a clip mask and scrollbars are needed. |
| if (createContentPaneAndScrollbarsIfNeeded()) |
| { |
| // Redo layout if scrollbars just got created or destroyed (because |
| // now we may have more or less space). |
| if (_autoLayout || forceLayout) |
| { |
| doingLayout = true; |
| super.validateDisplayList(); |
| doingLayout = false; |
| } |
| |
| // If a scrollbar was created, that may precipitate the need |
| // for a second scrollbar, so run it a second time. |
| createContentPaneAndScrollbarsIfNeeded(); |
| } |
| |
| // The relayout performed by the above calls |
| // to super.validateDisplayList() may result |
| // in new max scroll positions that are less |
| // than previously-set scroll positions. |
| // For example, when a maximally-scrolled container |
| // is resized to be larger, the new max scroll positions |
| // are reduced and the current scroll positions |
| // will be invalid unless we clamp them. |
| if (clampScrollPositions()) |
| scrollChildren(); |
| |
| if (contentPane) |
| { |
| vm = viewMetrics; |
| |
| // Set the position and size of the overlay . |
| if (effectOverlay) |
| { |
| effectOverlay.x = 0; |
| effectOverlay.y = 0; |
| effectOverlay.width = unscaledWidth; |
| effectOverlay.height = unscaledHeight; |
| } |
| |
| // Set the positions and sizes of the scrollbars. |
| /*if (horizontalScrollBar || verticalScrollBar) |
| { |
| // Get the view metrics and remove the thickness |
| // of the scrollbars from the view metrics. |
| // We can't simply get the border metrics, |
| // because some subclass (e.g.: Window) |
| // might add to the metrics. |
| if (verticalScrollBar && |
| verticalScrollPolicy == ScrollPolicy.ON) |
| { |
| vm.right -= verticalScrollBar.minWidth; |
| } |
| if (horizontalScrollBar && |
| horizontalScrollPolicy == ScrollPolicy.ON) |
| { |
| vm.bottom -= horizontalScrollBar.minHeight; |
| } |
| |
| if (horizontalScrollBar) |
| { |
| var w:Number = unscaledWidth - vm.left - vm.right; |
| if (verticalScrollBar) |
| w -= verticalScrollBar.minWidth; |
| |
| horizontalScrollBar.setActualSize( |
| w, horizontalScrollBar.minHeight); |
| |
| horizontalScrollBar.move(vm.left, |
| unscaledHeight - vm.bottom - |
| horizontalScrollBar.minHeight); |
| } |
| |
| if (verticalScrollBar) |
| { |
| var h:Number = unscaledHeight - vm.top - vm.bottom; |
| if (horizontalScrollBar) |
| h -= horizontalScrollBar.minHeight; |
| |
| verticalScrollBar.setActualSize( |
| verticalScrollBar.minWidth, h); |
| |
| verticalScrollBar.move(unscaledWidth - vm.right - |
| verticalScrollBar.minWidth, |
| vm.top); |
| } |
| |
| // Set the position of the box |
| // that covers the gap between the scroll bars. |
| if (whiteBox) |
| { |
| whiteBox.x = verticalScrollBar.x; |
| whiteBox.y = horizontalScrollBar.y; |
| } |
| }*/ |
| |
| contentPane.x = vm.left; |
| contentPane.y = vm.top; |
| |
| if (focusPane) |
| { |
| focusPane.x = vm.left |
| focusPane.y = vm.top; |
| } |
| |
| scrollChildren(); |
| } |
| |
| invalidateDisplayListFlag = false; |
| |
| // that blocks UI input as well as draws an alpha overlay. |
| // Make sure the blocker is correctly positioned and sized here. |
| if (blocker) |
| { |
| vm = viewMetrics; |
| |
| if (FlexVersion.compatibilityVersion >= FlexVersion.VERSION_4_0) |
| vm = EdgeMetrics.EMPTY; |
| |
| var bgColor:Object = enabled ? |
| null : |
| getStyle("backgroundDisabledColor"); |
| if (bgColor === null || isNaN(Number(bgColor))) |
| bgColor = getStyle("backgroundColor"); |
| |
| if (bgColor === null || isNaN(Number(bgColor))) |
| bgColor = 0xFFFFFF; |
| |
| var blockerAlpha:Number = getStyle("disabledOverlayAlpha"); |
| |
| if (isNaN(blockerAlpha)) |
| blockerAlpha = 0.6; |
| |
| blocker.x = vm.left; |
| blocker.y = vm.top; |
| |
| var widthToBlock:Number = unscaledWidth - (vm.left + vm.right); |
| var heightToBlock:Number = unscaledHeight - (vm.top + vm.bottom); |
| |
| blocker.graphics.clear(); |
| blocker.graphics.beginFill(uint(bgColor), blockerAlpha); |
| blocker.graphics.drawRect(0, 0, widthToBlock, heightToBlock); |
| blocker.graphics.endFill(); |
| |
| // Blocker must be in front of everything |
| rawChildren.setChildIndex(blocker, rawChildren.numChildren - 1); |
| } |
| |
| // trace("<<Container internalValidateDisplayList " + this); |
| } |
| |
| /** |
| * Respond to size changes by setting the positions and sizes |
| * of this container's children. |
| * |
| * <p>See the <code>UIComponent.updateDisplayList()</code> method for more information |
| * about the <code>updateDisplayList()</code> method.</p> |
| * |
| * <p>The <code>Container.updateDisplayList()</code> method sets the position |
| * and size of the Container container's border. |
| * In every subclass of Container, the subclass's <code>updateDisplayList()</code> |
| * method should call the <code>super.updateDisplayList()</code> method, |
| * so that the border is positioned properly.</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. |
| * |
| * @see mx.core.UIComponent |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| layoutChrome(unscaledWidth, unscaledHeight); |
| |
| if (scrollPositionChanged) |
| { |
| clampScrollPositions(); |
| |
| scrollChildren(); |
| |
| scrollPositionChanged = false; |
| } |
| |
| if (contentPane && contentPane.scrollRect) |
| { |
| // Draw content pane |
| |
| var backgroundColor:Object = enabled ? |
| null : |
| getStyle("backgroundDisabledColor"); |
| |
| if (backgroundColor === null || isNaN(Number(backgroundColor))) |
| backgroundColor = getStyle("backgroundColor"); |
| |
| var backgroundAlpha:Number = getStyle("backgroundAlpha"); |
| |
| if (!_clipContent || |
| isNaN(Number(backgroundColor)) || |
| backgroundColor === "" || |
| (!cacheAsBitmap)) |
| { |
| backgroundColor = null; |
| } |
| |
| // If there's a backgroundImage or background, unset |
| // opaqueBackground. |
| else if (getStyle("backgroundImage") || |
| getStyle("background")) |
| { |
| backgroundColor = null; |
| } |
| |
| // If the background is not opaque, unset opaqueBackground. |
| else if (backgroundAlpha != 1) |
| { |
| backgroundColor = null; |
| } |
| |
| contentPane.opaqueBackground = backgroundColor; |
| |
| // Set cacheAsBitmap only if opaqueBackground is also set (to avoid |
| // text anti-aliasing issue with device text on Windows). |
| contentPane.cacheAsBitmap = (backgroundColor != null); |
| } |
| |
| // The measure function isn't called if the width and height of |
| // the Tile are hard-coded. In that case, we compute the cellWidth |
| // and cellHeight now. |
| if (isNaN(cellWidth) || isNaN(cellHeight)) |
| findCellSize(); |
| |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| |
| var paddingLeft:Number = getStyle("paddingLeft"); |
| var paddingTop:Number = getStyle("paddingTop"); |
| |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| var verticalGap:Number = getStyle("verticalGap"); |
| |
| var horizontalAlign:String = getStyle("horizontalAlign"); |
| var verticalAlign:String = getStyle("verticalAlign"); |
| |
| var xPos:Number = paddingLeft; |
| var yPos:Number = paddingTop; |
| |
| var xOffset:Number; |
| var yOffset:Number; |
| |
| var n:int = numChildren; |
| var i:int; |
| var child:IUIComponent; |
| |
| if (direction == "horizontal") |
| { |
| var xEnd:Number = Math.ceil(unscaledWidth) - vm.right; |
| |
| for (i = 0; i < n; i++) |
| { |
| child = getLayoutChildAt(i); |
| |
| if (!child.includeInLayout) |
| continue; |
| |
| // Start a new row? |
| if (xPos + cellWidth > xEnd) |
| { |
| // Only if we have not just started one... |
| if (xPos != paddingLeft) |
| { |
| yPos += (cellHeight + verticalGap); |
| xPos = paddingLeft; |
| } |
| } |
| |
| setChildSize(child); // calls child.setActualSize() |
| |
| // Calculate the offsets to align the child in the cell. |
| xOffset = Math.floor(calcHorizontalOffset( |
| child.width, horizontalAlign)); |
| yOffset = Math.floor(calcVerticalOffset( |
| child.height, verticalAlign)); |
| |
| child.move(xPos + xOffset, yPos + yOffset); |
| |
| xPos += (cellWidth + horizontalGap); |
| } |
| } |
| else |
| { |
| var yEnd:Number = Math.ceil(unscaledHeight) - vm.bottom; |
| |
| for (i = 0; i < n; i++) |
| { |
| child = getLayoutChildAt(i); |
| |
| if (!child.includeInLayout) |
| continue; |
| |
| // Start a new column? |
| if (yPos + cellHeight > yEnd) |
| { |
| // Only if we have not just started one... |
| if (yPos != paddingTop) |
| { |
| xPos += (cellWidth + horizontalGap); |
| yPos = paddingTop; |
| } |
| } |
| |
| setChildSize(child); // calls child.setActualSize() |
| |
| // Calculate the offsets to align the child in the cell. |
| xOffset = Math.floor(calcHorizontalOffset( |
| child.width, horizontalAlign)); |
| yOffset = Math.floor(calcVerticalOffset( |
| child.height, verticalAlign)); |
| |
| child.move(xPos + xOffset, yPos + yOffset); |
| |
| yPos += (cellHeight + verticalGap); |
| } |
| } |
| |
| // Clear the cached cell size, because if a child's size changes |
| // it will be invalid. These cached values are only used to |
| // avoid recalculating in updateDisplayList() the same values |
| // that were just calculated in measure(). |
| // They should not persist across invalidation/validation cycles. |
| // (An alternative approach we tried was to clear these |
| // values in an override of invalidateSize(), but this gets called |
| // called indirectly by setChildSize() and child.move() inside |
| // the loops above. So we had to save and restore cellWidth |
| // and cellHeight around these calls in the loops, which is ugly.) |
| cellWidth = NaN; |
| cellHeight = NaN; |
| |
| _unscaledWidth = unscaledWidth; |
| _unscaledHeight = unscaledHeight; |
| |
| // The measure function isn't called if the width and height of |
| // the Tile are hard-coded. In that case, we compute the cellWidth |
| // and cellHeight now. |
| if (isNaN(cellWidth)) |
| findCellSize(); |
| |
| if (direction == "vertical") |
| layoutVertical(); |
| else |
| layoutHorizontal(); |
| } |
| |
| /** |
| * @copy mx.core.UIComponent#contentToGlobal() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function contentToGlobal(point:Point):Point |
| { |
| if (contentPane) |
| return contentPane.localToGlobal(point); |
| |
| return localToGlobal(point); |
| } |
| |
| /** |
| * @copy mx.core.UIComponent#globalToContent() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function globalToContent(point:Point):Point |
| { |
| if (contentPane) |
| return contentPane.globalToLocal(point); |
| |
| return globalToLocal(point); |
| } |
| |
| /** |
| * @copy mx.core.UIComponent#contentToLocal() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function contentToLocal(point:Point):Point |
| { |
| if (!contentPane) |
| return point; |
| |
| point = contentToGlobal(point); |
| return globalToLocal(point); |
| } |
| |
| /** |
| * @copy mx.core.UIComponent#localToContent() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function localToContent(point:Point):Point |
| { |
| if (!contentPane) |
| return point; |
| |
| point = localToGlobal(point); |
| return globalToContent(point); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| var allStyles:Boolean = styleProp == null || styleProp == "styleName"; |
| |
| // Check to see if this is one of the style properties that is known |
| // to affect page layout. |
| if (allStyles || styleManager.isSizeInvalidatingStyle(styleProp)) |
| { |
| // Some styles, such as horizontalAlign and verticalAlign, |
| // affect the layout of this object's children without changing the |
| // view's size. This function forces the view to be remeasured |
| // and layed out. |
| invalidateDisplayList(); |
| } |
| |
| // Replace the borderSkin |
| if (allStyles || styleProp == "borderSkin") |
| { |
| if (border) |
| { |
| rawChildren.removeChild(DisplayObject(border)); |
| border = null; |
| createBorder(); |
| } |
| } |
| |
| // Create a border object, if none previously existed and |
| // one is needed now. |
| if (allStyles || |
| styleProp == "borderStyle" || |
| styleProp == "backgroundColor" || |
| styleProp == "backgroundImage" || |
| styleProp == "mouseShield" || |
| styleProp == "mouseShieldChildren") |
| { |
| createBorder(); |
| } |
| |
| super.styleChanged(styleProp); |
| |
| // Check to see if this is one of the style properties that is known. |
| // to affect page layout. |
| if (allStyles || |
| styleManager.isSizeInvalidatingStyle(styleProp)) |
| { |
| invalidateViewMetricsAndPadding(); |
| } |
| } |
| |
| /** |
| * @private |
| * Call the styleChanged method on children of this container |
| * |
| * Notify chrome children immediately, and recursively call this |
| * function for all descendants of the chrome children. We recurse |
| * regardless of the recursive flag because one of the descendants |
| * might have a styleName property that points to this object. |
| * |
| * If recursive is true, then also notify content children ... but |
| * do it later. Notification is deferred so that multiple calls to |
| * setStyle can be batched up into one traversal. |
| */ |
| override public function notifyStyleChangeInChildren( |
| styleProp:String, recursive:Boolean):void |
| { |
| // Notify chrome children immediately, recursively calling this |
| // this function |
| var n:int = super.numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| // Is this a chrome child? |
| if (contentPane || |
| i < _firstChildIndex || |
| i >= _firstChildIndex + _numChildren) |
| { |
| var child:ISimpleStyleClient = super.getChildAt(i) as ISimpleStyleClient; |
| if (child) |
| { |
| child.styleChanged(styleProp); |
| if (child is IStyleClient) |
| IStyleClient(child).notifyStyleChangeInChildren(styleProp, recursive); |
| } |
| } |
| } |
| |
| // If recursive, then remember to notify the content children later |
| if (recursive) |
| { |
| // If multiple styleProps have changed, set changedStyles to |
| // MULTIPLE_PROPERTIES. Otherwise, set it to the name of the |
| // changed property. |
| changedStyles = (changedStyles != null || styleProp == null) ? |
| MULTIPLE_PROPERTIES : styleProp; |
| invalidateProperties(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function regenerateStyleCache(recursive:Boolean):void |
| { |
| super.regenerateStyleCache(recursive); |
| |
| if (contentPane) |
| { |
| // Do the same thing as UIComponent, but don't check the child's index to |
| // ascertain that it's a content child (we already know that here). |
| |
| var n:int = contentPane.numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:DisplayObject = getChildAt(i); |
| |
| if (child is UIComponent) |
| { |
| // Does this object already have a proto chain? If not, |
| // there's no need to regenerate a new one. |
| if (UIComponent(child).inheritingStyles != StyleProtoChain.STYLE_UNINITIALIZED) |
| UIComponent(child).regenerateStyleCache(recursive); |
| } |
| else if (child is IUITextField && IUITextField(child).inheritingStyles) |
| { |
| StyleProtoChain.initTextField(IUITextField(child)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Used internally by the Dissolve Effect to add the overlay to the chrome of a container. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function attachOverlay():void |
| { |
| rawChildren_addChild(effectOverlay); |
| } |
| |
| /** |
| * Fill an overlay object which is always the topmost child in the container. |
| * This method is used |
| * by the Dissolve effect; never call it directly. It is called |
| * internally by the <code>addOverlay()</code> method. |
| * |
| * The Container fills the overlay object so it covers the viewable area returned |
| * by the <code>viewMetrics</code> property and uses the <code>cornerRadius</code> style. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override mx_internal function fillOverlay(overlay:UIComponent, color:uint, |
| targetArea:RoundedRectangle = null):void |
| { |
| var vm:EdgeMetrics = viewMetrics; |
| var cornerRadius:Number = 0; //getStyle("cornerRadius"); |
| |
| if (!targetArea) |
| { |
| targetArea = new RoundedRectangle( |
| vm.left, vm.top, |
| unscaledWidth - vm.right - vm.left, |
| unscaledHeight - vm.bottom - vm.top,cornerRadius); |
| } |
| |
| if (isNaN(targetArea.x) || isNaN(targetArea.y) || |
| isNaN(targetArea.width) || isNaN(targetArea.height) || |
| isNaN(targetArea.cornerRadius)) |
| return; |
| |
| var g:Graphics = overlay.graphics; |
| g.clear(); |
| g.beginFill(color); |
| g.drawRoundRect(targetArea.x, targetArea.y, |
| targetArea.width, targetArea.height, |
| targetArea.cornerRadius * 2, |
| targetArea.cornerRadius * 2); |
| g.endFill(); |
| } |
| |
| /** |
| * Executes all the data bindings on this Container. Flex calls this method |
| * automatically once a Container has been created to cause any data bindings that |
| * have destinations inside of it to execute. |
| * |
| * Workaround for MXML container/bindings problem (177074): |
| * override Container.executeBindings() to prefer descriptor.document over parentDocument in the |
| * call to BindingManager.executeBindings(). |
| * |
| * This should always provide the correct behavior for instances created by descriptor, and will |
| * provide the original behavior for procedurally-created instances. (The bug may or may not appear |
| * in the latter case.) |
| * |
| * A more complete fix, guaranteeing correct behavior in both non-DI and reparented-component |
| * scenarios, is anticipated for updater 1. |
| * |
| * @param recurse If <code>false</code>, then only execute the bindings |
| * on this Container. |
| * If <code>true</code>, then also execute the bindings on this |
| * container's children, grandchildren, |
| * great-grandchildren, and so on. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function executeBindings(recurse:Boolean = false):void |
| { |
| var bindingsHost:Object = descriptor && descriptor.document ? descriptor.document : parentDocument; |
| BindingManager.executeBindings(bindingsHost, id, this); |
| |
| if (recurse) |
| executeChildBindings(recurse); |
| } |
| |
| /** |
| * @private |
| * Prepare the Object for printing |
| * |
| * @see mx.printing.FlexPrintJob |
| */ |
| override public function prepareToPrint(target:IFlexDisplayObject):Object |
| { |
| var rect:Rectangle = (contentPane && contentPane.scrollRect) ? contentPane.scrollRect : null; |
| |
| if (rect) |
| contentPane.scrollRect = null; |
| |
| super.prepareToPrint(target); |
| |
| return rect; |
| } |
| |
| /** |
| * @private |
| * After printing is done |
| * |
| * @see mx.printing.FlexPrintJob |
| */ |
| override public function finishPrint(obj:Object, target:IFlexDisplayObject):void |
| { |
| if (obj) |
| contentPane.scrollRect = Rectangle(obj); |
| |
| super.finishPrint(obj,target); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Child management |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override mx_internal function addingChild(child:DisplayObject):void |
| { |
| // Throw an RTE if child is not an IUIComponent. |
| var uiChild:IUIComponent = IUIComponent(child); |
| |
| // Set the child's virtual parent, nestLevel, document, etc. |
| super.addingChild(child); |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| if (!contentPane) |
| { |
| // If this is the first content child, then any chrome |
| // that already exists is positioned in front of it. |
| // If other content children already existed, then set the |
| // depth of this object to be just behind the existing |
| // content children. |
| if (_numChildren == 0) |
| _firstChildIndex = super.numChildren; |
| |
| // Increment the number of content children. |
| _numChildren++; |
| } |
| |
| if (contentPane && !autoLayout) |
| { |
| forceLayout = true; |
| // weak reference |
| UIComponentGlobals.layoutManager.addEventListener( |
| FlexEvent.UPDATE_COMPLETE, layoutCompleteHandler, false, 0, true); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function childAdded(child:DisplayObject):void |
| { |
| if (hasEventListener("childrenChanged")) |
| dispatchEvent(new Event("childrenChanged")); |
| |
| if (hasEventListener(ChildExistenceChangedEvent.CHILD_ADD)) |
| { |
| var event:ChildExistenceChangedEvent = |
| new ChildExistenceChangedEvent( |
| ChildExistenceChangedEvent.CHILD_ADD); |
| event.relatedObject = child; |
| dispatchEvent(event); |
| } |
| |
| if (hasEventListener(FlexEvent.ADD)) |
| child.dispatchEvent(new FlexEvent(FlexEvent.ADD)); |
| |
| super.childAdded(child); // calls createChildren() |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function removingChild(child:DisplayObject):void |
| { |
| super.removingChild(child); |
| |
| if (hasEventListener(FlexEvent.REMOVE)) |
| child.dispatchEvent(new FlexEvent(FlexEvent.REMOVE)); |
| |
| if (hasEventListener(ChildExistenceChangedEvent.CHILD_REMOVE)) |
| { |
| var event:ChildExistenceChangedEvent = |
| new ChildExistenceChangedEvent( |
| ChildExistenceChangedEvent.CHILD_REMOVE); |
| event.relatedObject = child; |
| dispatchEvent(event); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function childRemoved(child:DisplayObject):void |
| { |
| super.childRemoved(child); |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| if (!contentPane) |
| { |
| _numChildren--; |
| |
| if (_numChildren == 0) |
| _firstChildIndex = super.numChildren; |
| } |
| |
| if (contentPane && !autoLayout) |
| { |
| forceLayout = true; |
| // weak reference |
| UIComponentGlobals.layoutManager.addEventListener( |
| FlexEvent.UPDATE_COMPLETE, layoutCompleteHandler, false, 0, true); |
| } |
| |
| if (hasEventListener("childrenChanged")) |
| dispatchEvent(new Event("childrenChanged")); |
| } |
| |
| [Bindable("childrenChanged")] |
| |
| /** |
| * Returns an Array of DisplayObject objects consisting of the content children |
| * of the container. |
| * This array does <b>not</b> include the DisplayObjects that implement |
| * the container's display elements, such as its border and |
| * the background image. |
| * |
| * @return Array of DisplayObject objects consisting of the content children |
| * of the container. |
| * |
| * @see #rawChildren |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function getChildren():Array |
| { |
| var results:Array = []; |
| |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| results.push(getChildAt(i)); |
| } |
| |
| return results; |
| } |
| |
| /** |
| * Removes all children from the child list of this container. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function removeAllChildren():void |
| { |
| while (numChildren > 0) |
| { |
| removeChildAt(0); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Deferred instantiation |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * For containers, we need to ensure that at most one set of children |
| * has been specified for the component. |
| * There are two ways to specify multiple sets of children: |
| * a) the component itself, as well as an instance of the component, |
| * might specify children; |
| * b) both a base and derived component might specify children. |
| * Case (a) is handled in initialize(), above. |
| * Case (b) is handled here. |
| * This method is called in overrides of initialize() |
| * that are generated for MXML components. |
| */ |
| mx_internal function setDocumentDescriptor(desc:UIComponentDescriptor):void |
| { |
| if (processedDescriptors) |
| return; |
| |
| if (_documentDescriptor && _documentDescriptor.properties.childDescriptors) |
| { |
| if (desc.properties.childDescriptors) |
| { |
| var message:String = resourceManager.getString( |
| "core", "multipleChildSets_ClassAndSubclass"); |
| throw new Error(message); |
| } |
| } |
| else |
| { |
| _documentDescriptor = desc; |
| _documentDescriptor.document = this; |
| } |
| } |
| |
| /** |
| * @private |
| * Used by subclasses, so must be public. |
| */ |
| mx_internal function setActualCreationPolicies(policy:String):void |
| { |
| actualCreationPolicy = policy; |
| |
| // Recursively set the actualCreationPolicy of all descendant |
| // containers which have an undefined creationPolicy. |
| var childPolicy:String = policy; |
| |
| if (policy == ContainerCreationPolicy.QUEUED) |
| childPolicy = ContainerCreationPolicy.AUTO; |
| |
| //trace("setActualCreationPolicies policy", policy, "childPolicy", childPolicy); |
| |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IFlexDisplayObject = IFlexDisplayObject(getChildAt(i)); |
| /*if (child is Container) |
| { |
| var childContainer:Container = Container(child); |
| if (childContainer.creationPolicy == null) |
| childContainer.setActualCreationPolicies(childPolicy); |
| }*/ |
| } |
| } |
| |
| |
| /** |
| * Iterate through the Array of <code>childDescriptors</code>, |
| * and call the <code>createComponentFromDescriptor()</code> method for each one. |
| * |
| * <p>If the value of the container's <code>creationPolicy</code> property is |
| * <code>ContainerCreationPolicy.ALL</code>, then this method is called |
| * automatically during the initialization sequence.</p> |
| * |
| * <p>If the value of the container's <code>creationPolicy</code> is |
| * <code>ContainerCreationPolicy.AUTO</code>, |
| * then this method is called automatically when the |
| * container's children are about to become visible.</p> |
| * |
| * <p>If the value of the container's <code>creationPolicy</code> property is |
| * <code>ContainerCreationPolicy.NONE</code>, |
| * then you should call this function |
| * when you want to create this container's children.</p> |
| * |
| * @param recurse If <code>true</code>, recursively |
| * create components. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function createComponentsFromDescriptors( |
| recurse:Boolean = true):void |
| { |
| numChildrenBefore = numChildren; |
| |
| createdComponents = []; |
| |
| var n:int = childDescriptors ? childDescriptors.length : 0; |
| for (var i:int = 0; i < n; i++) |
| { |
| var component:IFlexDisplayObject = |
| createComponentFromDescriptor(childDescriptors[i], recurse); |
| |
| createdComponents.push(component); |
| } |
| |
| if (creationPolicy == ContainerCreationPolicy.QUEUED || |
| creationPolicy == ContainerCreationPolicy.NONE) |
| { |
| UIComponentGlobals.layoutManager.usePhasedInstantiation = false; |
| } |
| |
| numChildrenCreated = numChildren - numChildrenBefore; |
| |
| processedDescriptors = true; |
| dispatchEvent(new FlexEvent(FlexEvent.CONTENT_CREATION_COMPLETE)); |
| } |
| |
| /** |
| * Performs the equivalent action of calling |
| * the <code>createComponentsFromDescriptors(true)</code> method for containers |
| * that implement the IDeferredContentOwner interface to support deferred instantiation. |
| * |
| * @see #createComponentsFromDescriptors() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function createDeferredContent():void |
| { |
| createComponentsFromDescriptors(true); |
| } |
| |
| /** |
| * Given a single UIComponentDescriptor, create the corresponding |
| * component and add the component as a child of this container. |
| * |
| * <p>This method instantiates the new object but does not add it to the display list, so the object does not |
| * appear on the screen by default. To add the new object to the display list, call the <code>validateNow()</code> |
| * method on the container after calling the <code>createComponentFromDescriptor()</code> method, |
| * as the following example shows: |
| * <pre> |
| * myVBox.createComponentFromDescriptor(myVBox.childDescriptors[0],false); |
| * myVBox.validateNow(); |
| * </pre> |
| * </p> |
| * |
| * <p>Alternatively, you can call the <code>createComponentsFromDescriptors()</code> method on the |
| * container to create all components at one time. You are not required to call the <code>validateNow()</code> |
| * method after calling the <code>createComponentsFromDescriptors()</code> method.</p> |
| * |
| * @param descriptor The UIComponentDescriptor for the |
| * component to be created. This argument is either a |
| * UIComponentDescriptor object or the index of one of the container's |
| * children (an integer between 0 and n-1, where n is the total |
| * number of children of this container). |
| * |
| * @param recurse If <code>false</code>, create this component |
| * but none of its children. |
| * If <code>true</code>, after creating the component, Flex calls |
| * the <code>createComponentsFromDescriptors()</code> method to create all or some |
| * of its children, based on the value of the component's <code>creationPolicy</code> property. |
| * |
| * @return The component that is created. |
| * |
| * @see mx.core.UIComponentDescriptor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function createComponentFromDescriptor( |
| descriptor:ComponentDescriptor, |
| recurse:Boolean):IFlexDisplayObject |
| { |
| // If recurse is 'false', we create this component but none |
| // of its children. |
| |
| // If recurse is 'true', after creating the component we call |
| // createComponentsFromDescriptors() to create all or some |
| // of its children, based on the component's |
| // actualContainerCreationPolicy. |
| |
| var childDescriptor:UIComponentDescriptor = |
| UIComponentDescriptor(descriptor); |
| |
| var childProperties:Object = childDescriptor.properties; |
| |
| // This function could be asked to create the same child component |
| // twice. That's fine if the child component is inside a repeater. |
| // In other cases, though, we want to avoid creating the same child |
| // twice. |
| // |
| // The hasChildMatchingDescriptor function is a bit expensive, so |
| // we try to avoid calling it if we know we're inside the first call |
| // to createComponents. |
| if ((numChildrenBefore != 0 || numChildrenCreated != -1) && |
| childDescriptor.instanceIndices == null && |
| hasChildMatchingDescriptor(childDescriptor)) |
| { |
| return null; |
| } |
| |
| // Turn on the three-frame instantiation scheme. |
| UIComponentGlobals.layoutManager.usePhasedInstantiation = true; |
| |
| // Create the new child object and give it a unique name |
| var childType:Class = childDescriptor.type; |
| var child:IDeferredInstantiationUIComponent = new childType(); |
| child.id = childDescriptor.id; |
| if (child.id && child.id != "") |
| child.name = child.id; |
| |
| // Copy property values from the descriptor |
| // to the newly created component. |
| child.descriptor = childDescriptor; |
| if (childProperties.childDescriptors && child is IContainer && (child as Object).hasOwnProperty("_childDescriptors")) |
| { |
| (child as Object)._childDescriptors = |
| childProperties.childDescriptors; |
| delete childProperties.childDescriptors; |
| } |
| for (var p:String in childProperties) |
| { |
| child[p] = childProperties[p]; |
| } |
| |
| // Set a flag indicating whether we should call |
| // this function recursively. |
| if (child is IContainer && (child as Object).hasOwnProperty("recursionFlag")) |
| (child as Object).recursionFlag = recurse; |
| |
| if (childDescriptor.instanceIndices) |
| { |
| if (child is IRepeaterClient) |
| { |
| var rChild:IRepeaterClient = IRepeaterClient(child); |
| rChild.instanceIndices = childDescriptor.instanceIndices; |
| rChild.repeaters = childDescriptor.repeaters; |
| rChild.repeaterIndices = childDescriptor.repeaterIndices; |
| } |
| } |
| |
| if (child is IStyleClient) |
| { |
| var scChild:IStyleClient = IStyleClient(child); |
| |
| // Initialize the CSSStyleDeclaration. |
| // It is used by initProtoChain(), which is called by addChild(). |
| if (childDescriptor.stylesFactory != null) |
| { |
| if (!scChild.styleDeclaration) |
| scChild.styleDeclaration = new CSSStyleDeclaration(null, styleManager); |
| scChild.styleDeclaration.factory = |
| childDescriptor.stylesFactory; |
| } |
| } |
| |
| // For each event, register the handle method, which is specified in |
| // the descriptor by name, as one of the child's event listeners. |
| var childEvents:Object = childDescriptor.events; |
| if (childEvents) |
| { |
| for (var eventName:String in childEvents) |
| { |
| var eventHandler:String = childEvents[eventName]; |
| child.addEventListener(eventName, |
| childDescriptor.document[eventHandler]); |
| } |
| } |
| |
| // For each effect, register the EffectManager as an event listener |
| var childEffects:Array = childDescriptor.effects; |
| if (childEffects) |
| child.registerEffects(childEffects); |
| |
| if (child is IRepeaterClient) |
| IRepeaterClient(child).initializeRepeaterArrays(this); |
| |
| // If an MXML id was specified, create a property with this name on |
| // the MXML document object whose value references the child. |
| // This should be the last step in initializing the child, so that |
| // it can't be referenced until initialization is complete. |
| // However, it must be done before executing executeBindings(). |
| child.createReferenceOnParentDocument( |
| IFlexDisplayObject(childDescriptor.document)); |
| |
| if (!child.document) |
| child.document = childDescriptor.document; |
| |
| // Repeaters don't get added as children of the Container, |
| // so they have their own initialization sequence. |
| if (child is IRepeater) |
| { |
| // Add this repeater to the list maintained by the parent |
| // container |
| if (!childRepeaters) |
| childRepeaters = []; |
| childRepeaters.push(child); |
| |
| // The Binding Manager may have some data that it wants to bind to |
| // various properties of the newly created repeater. |
| child.executeBindings(); |
| |
| IRepeater(child).initializeRepeater(this, recurse); |
| } |
| else |
| { |
| // This needs to run before child.executeBindings(), because |
| // executeBindings() depends on the parent being set. |
| addChild(DisplayObject(child)); |
| |
| child.executeBindings(); |
| |
| if (creationPolicy == ContainerCreationPolicy.QUEUED || |
| creationPolicy == ContainerCreationPolicy.NONE) |
| { |
| child.addEventListener(FlexEvent.CREATION_COMPLETE, |
| creationCompleteHandler); |
| } |
| } |
| |
| // Return a reference to the child UIComponent that was just created. |
| return child; |
| } |
| |
| /** |
| * @private |
| */ |
| private function hasChildMatchingDescriptor( |
| descriptor:UIComponentDescriptor):Boolean |
| { |
| // Optimization: If the descriptor has an id but no such id |
| // reference exists on the document, then there are no children |
| // in this container with that descriptor. |
| // (On the other hand, if there IS an id reference on the document, |
| // we can't be sure that it is for a child of this container. It |
| // could be an indexed reference in which some instances are |
| // in other containers. This happens when you have |
| // <Repeater> |
| // <VBox> |
| // <Button> |
| var id:String = descriptor.id; |
| if (id != null && (id in document) && document[id] == null) |
| return false; |
| |
| var n:int = numChildren; |
| var i:int; |
| |
| // Iterate over this container's children, looking for one |
| // that matches this descriptor |
| for (i = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| if (child is IDeferredInstantiationUIComponent && |
| IDeferredInstantiationUIComponent(child) |
| .descriptor == descriptor) |
| { |
| return true; |
| } |
| } |
| |
| // Also check this container's Repeaters, if there are any. |
| if (childRepeaters) |
| { |
| n = childRepeaters.length; |
| for (i = 0; i < n; i++) |
| { |
| if (IDeferredInstantiationUIComponent(childRepeaters[i]) |
| .descriptor == descriptor) |
| { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Support for rawChildren access |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * This class overrides addChild() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_addChild(child:DisplayObject):DisplayObject |
| { |
| // This method is only used to implement rawChildren.addChild(), |
| // so the child being added is assumed to be a non-content child. |
| // (You would use just addChild() to add a content child.) |
| // If there are no content children, the new child is placed |
| // in the pre-content partition. |
| // If there are content children, the new child is placed |
| // in the post-content partition. |
| if (_numChildren == 0) |
| _firstChildIndex++; |
| |
| super.addingChild(child); |
| $addChild(child); |
| super.childAdded(child); |
| |
| dispatchEvent(new Event("childrenChanged")); |
| |
| return child; |
| } |
| |
| /** |
| * @private |
| * This class overrides addChildAt() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_addChildAt(child:DisplayObject, |
| index:int):DisplayObject |
| { |
| if (_firstChildIndex < index && |
| index < _firstChildIndex + _numChildren + 1) |
| { |
| _numChildren++; |
| } |
| else if (index <= _firstChildIndex) |
| { |
| _firstChildIndex++; |
| } |
| |
| super.addingChild(child); |
| $addChildAt(child, index); |
| super.childAdded(child); |
| |
| dispatchEvent(new Event("childrenChanged")); |
| |
| return child; |
| } |
| |
| /** |
| * @private |
| * This class overrides removeChild() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_removeChild( |
| child:DisplayObject):DisplayObject |
| { |
| var index:int = rawChildren_getChildIndex(child); |
| return rawChildren_removeChildAt(index); |
| } |
| |
| /** |
| * @private |
| * This class overrides removeChildAt() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_removeChildAt(index:int):DisplayObject |
| { |
| var child:DisplayObject = super.getChildAt(index); |
| |
| super.removingChild(child); |
| $removeChildAt(index); |
| super.childRemoved(child); |
| |
| if (_firstChildIndex < index && |
| index < _firstChildIndex + _numChildren) |
| { |
| _numChildren--; |
| } |
| else if (_numChildren == 0 || index < _firstChildIndex) |
| { |
| _firstChildIndex--; |
| } |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("childrenChanged")); |
| |
| return child; |
| } |
| |
| /** |
| * @private |
| * This class overrides getChildAt() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_getChildAt(index:int):DisplayObject |
| { |
| return super.getChildAt(index); |
| } |
| |
| /** |
| * @private |
| * This class overrides getChildByName() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_getChildByName(name:String):DisplayObject |
| { |
| return super.getChildByName(name); |
| } |
| |
| /** |
| * @private |
| * This class overrides getChildIndex() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_getChildIndex(child:DisplayObject):int |
| { |
| return super.getChildIndex(child); |
| } |
| |
| /** |
| * @private |
| * This class overrides setChildIndex() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_setChildIndex(child:DisplayObject, |
| newIndex:int):void |
| { |
| var oldIndex:int = super.getChildIndex(child); |
| |
| super.setChildIndex(child, newIndex); |
| |
| // Is this a piece of chrome that was previously before |
| // the content children and is now after them in the list? |
| if (oldIndex < _firstChildIndex && newIndex >= _firstChildIndex) |
| { |
| _firstChildIndex--; |
| } |
| |
| // Is this a piece of chrome that was previously after |
| // the content children and is now before them in the list? |
| else if (oldIndex >= _firstChildIndex && newIndex <= _firstChildIndex) |
| { |
| _firstChildIndex++ |
| } |
| |
| dispatchEvent(new Event("childrenChanged")); |
| } |
| |
| /** |
| * @private |
| * This class overrides getObjectsUnderPoint() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_getObjectsUnderPoint(pt:Point):Array |
| { |
| return super.getObjectsUnderPoint(pt); |
| } |
| |
| /** |
| * @private |
| * This class overrides contains() to deal with only content children, |
| * so in order to implement the rawChildren property we need |
| * a parallel method that deals with all children. |
| */ |
| mx_internal function rawChildren_contains(child:DisplayObject):Boolean |
| { |
| return super.contains(child); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Chrome management |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Respond to size changes by setting the positions and sizes |
| * of this container's borders. |
| * This is an advanced method that you might override |
| * when creating a subclass of Container. |
| * |
| * <p>Flex calls the <code>layoutChrome()</code> method when the |
| * container is added to a parent container using the <code>addChild()</code> method, |
| * and when the container's <code>invalidateDisplayList()</code> method is called.</p> |
| * |
| * <p>The <code>Container.layoutChrome()</code> method is called regardless of the |
| * value of the <code>autoLayout</code> property.</p> |
| * |
| * <p>The <code>Container.layoutChrome()</code> method sets the |
| * position and size of the Container container's border. |
| * In every subclass of Container, the subclass's <code>layoutChrome()</code> |
| * method should call the <code>super.layoutChrome()</code> method, |
| * so that the border is positioned properly.</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 Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function layoutChrome(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| // Border covers the whole thing. |
| if (border) |
| { |
| updateBackgroundImageRect(); |
| |
| border.move(0, 0); |
| border.setActualSize(unscaledWidth, unscaledHeight); |
| } |
| } |
| |
| /** |
| * Creates the container's border skin |
| * if it is needed and does not already exist. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function createBorder():void |
| { |
| if (!border && isBorderNeeded()) |
| { |
| var borderClass:Class = getStyle("borderSkin"); |
| |
| if (borderClass != null) |
| { |
| border = new borderClass(); |
| border.name = "border"; |
| |
| if (border is IUIComponent) |
| IUIComponent(border).enabled = enabled; |
| if (border is ISimpleStyleClient) |
| ISimpleStyleClient(border).styleName = this; |
| |
| // Add the border behind all the children. |
| rawChildren.addChildAt(DisplayObject(border), 0); |
| |
| invalidateDisplayList(); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| * Store references to the default border classes here so we don't have to look them up |
| * every time. |
| */ |
| private static var haloBorder:Class; |
| private static var sparkBorder:Class; |
| private static var sparkContainerBorder:Class; |
| private static var didLookup:Boolean = false; |
| |
| private static function getDefinition(name:String):Class |
| { |
| var result:Object = null; |
| |
| try |
| { |
| result = getDefinitionByName(name); |
| } |
| catch(e:Error) |
| { |
| } |
| |
| return result as Class; |
| } |
| /** |
| * @private |
| */ |
| private function isBorderNeeded():Boolean |
| { |
| //trace("isBorderNeeded",this,"ms",getStyle("mouseShield"),"borderStyle",getStyle("borderStyle")); |
| |
| // If the borderSkin is a custom class, always assume the border is needed. |
| var c:Class = getStyle("borderSkin"); |
| |
| if (!didLookup) |
| { |
| // Lookup the default border classes by name to avoid a linkage dependency. |
| // Note: this code assumes either HaloBorder or spark BorderSkin is the default border skin. |
| // If this is changed in defaults.css, it must also be changed here. |
| haloBorder = getDefinition("mx.skins.halo::HaloBorder"); |
| sparkBorder = getDefinition("mx.skins.spark::BorderSkin"); |
| sparkContainerBorder = getDefinition("mx.skins.spark::ContainerBorderSkin"); |
| didLookup = true; |
| } |
| |
| if (!(c == haloBorder || c == sparkBorder || c == sparkContainerBorder)) |
| return true; |
| |
| var v:Object = getStyle("borderStyle"); |
| if (v) |
| { |
| // If borderStyle is "none", then only create a border if the mouseShield style is true |
| // (meaning that there is a mouse event listener on this view). We don't create a border |
| // if our parent's mouseShieldChildren style is true. |
| if ((v != "none") || (v == "none" && getStyle("mouseShield"))) |
| { |
| return true; |
| } |
| } |
| |
| v = getStyle("contentBackgroundColor"); |
| if (c == sparkBorder && v !== null) |
| return true; |
| |
| v = getStyle("backgroundColor"); |
| if (v !== null && v !== "") |
| return true; |
| |
| v = getStyle("backgroundImage"); |
| return v != null && v != ""; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function invalidateViewMetricsAndPadding():void |
| { |
| _viewMetricsAndPadding = null; |
| } |
| |
| /** |
| * @private |
| */ |
| private function createOrDestroyBlocker():void |
| { |
| // If this container is being enabled and a blocker exists, |
| // remove it. If this container is being disabled and a |
| // blocker doesn't exist, create it. |
| if (enabled) |
| { |
| if (blocker) |
| { |
| rawChildren.removeChild(blocker); |
| blocker = null; |
| } |
| } |
| else |
| { |
| if (!blocker) |
| { |
| blocker = new FlexSprite(); |
| blocker.name = "blocker"; |
| blocker.mouseEnabled = true; |
| rawChildren.addChild(blocker); |
| |
| blocker.addEventListener(MouseEvent.CLICK, |
| blocker_clickHandler); |
| |
| // If the focus is a child of ours, we clear it here. |
| var o:DisplayObject = |
| focusManager ? |
| DisplayObject(focusManager.getFocus()) : |
| null; |
| |
| while (o) |
| { |
| if (o == this) |
| { |
| var sm:ISystemManager = systemManager; |
| if (sm && sm.stage) |
| sm.stage.focus = null; |
| break; |
| } |
| o = o.parent; |
| } |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function updateBackgroundImageRect():void |
| { |
| var rectBorder:IRectangularBorder = border as IRectangularBorder; |
| |
| if (!rectBorder) |
| return; |
| |
| // If viewableWidth and viewableHeight are 0, we don't have any |
| // scrollbars or clipped content. |
| if (viewableWidth == 0 && viewableHeight == 0) |
| { |
| rectBorder.backgroundImageBounds = null; |
| return; |
| } |
| |
| var vm:EdgeMetrics = viewMetrics; |
| var bkWidth:Number = viewableWidth ? viewableWidth : |
| unscaledWidth - vm.left - vm.right; |
| var bkHeight:Number = viewableHeight ? viewableHeight : |
| unscaledHeight - vm.top - vm.bottom; |
| |
| if (getStyle("backgroundAttachment") == "fixed") |
| { |
| rectBorder.backgroundImageBounds = new Rectangle(vm.left, vm.top, |
| bkWidth, bkHeight); |
| } |
| else |
| { |
| rectBorder.backgroundImageBounds = new Rectangle(vm.left, vm.top, |
| Math.max(scrollableWidth, bkWidth), |
| Math.max(scrollableHeight, bkHeight)); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Scrolling |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function createContentPaneAndScrollbarsIfNeeded():Boolean |
| { |
| var bounds:Rectangle; |
| var changed:Boolean = false; |
| |
| // No mask is needed if clipping isn't active |
| if (_clipContent) |
| { |
| // Get the new scrollable width, which is the equal to the right |
| // edge of the rightmost child. Also get the new scrollable height. |
| bounds = getScrollableRect(); |
| |
| if (border) |
| updateBackgroundImageRect(); |
| |
| return changed; |
| } |
| else |
| { |
| // Get scrollableWidth and scrollableHeight for scrollChildren() |
| bounds = getScrollableRect(); |
| scrollableWidth = bounds.right; |
| scrollableHeight = bounds.bottom; |
| |
| if (changed && border) |
| updateBackgroundImageRect(); |
| |
| return changed; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function getScrollableRect():Rectangle |
| { |
| var left:Number = 0; |
| var top:Number = 0; |
| var right:Number = 0; |
| var bottom:Number = 0; |
| |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var x:Number; |
| var y:Number; |
| var width:Number; |
| var height:Number; |
| |
| var child:DisplayObject = getChildAt(i); |
| if (child is IUIComponent) |
| { |
| if (!IUIComponent(child).includeInLayout) |
| continue; |
| var uic:IUIComponent = PostScaleAdapter.getCompatibleIUIComponent(child); |
| width = uic.width; |
| height = uic.height; |
| x = uic.x; |
| y = uic.y; |
| } |
| else |
| { |
| width = child.width; |
| height = child.height; |
| x = child.x; |
| y = child.y; |
| } |
| |
| left = Math.min(left, x); |
| top = Math.min(top, y); |
| |
| // width/height can be NaN if using percentages and |
| // hasn't been layed out yet. |
| if (!isNaN(width)) |
| right = Math.max(right, x + width); |
| if (!isNaN(height)) |
| bottom = Math.max(bottom, y + height); |
| } |
| |
| // Add in the right/bottom margins and view metrics. |
| var vm:EdgeMetrics = viewMetrics; |
| |
| var bounds:Rectangle = new Rectangle(); |
| bounds.left = left; |
| bounds.top = top; |
| bounds.right = right; |
| bounds.bottom = bottom; |
| |
| if (usePadding) |
| { |
| bounds.right += getStyle("paddingRight"); |
| bounds.bottom += getStyle("paddingBottom"); |
| } |
| |
| return bounds; |
| } |
| |
| |
| /** |
| * @private |
| * Ensures that horizontalScrollPosition is in the range |
| * from 0 through maxHorizontalScrollPosition and that |
| * verticalScrollPosition is in the range from 0 through |
| * maxVerticalScrollPosition. |
| * Returns true if either horizontalScrollPosition or |
| * verticalScrollPosition was changed to ensure this. |
| */ |
| private function clampScrollPositions():Boolean |
| { |
| var changed:Boolean = false; |
| |
| // Clamp horizontalScrollPosition to the range |
| // 0 through maxHorizontalScrollPosition. |
| // If horizontalScrollBar doesn't exist, |
| // maxHorizontalScrollPosition will be 0. |
| if (_horizontalScrollPosition < 0) |
| { |
| _horizontalScrollPosition = 0; |
| changed = true; |
| } |
| else if (_horizontalScrollPosition > maxHorizontalScrollPosition) |
| { |
| _horizontalScrollPosition = maxHorizontalScrollPosition; |
| changed = true; |
| } |
| |
| // Clamp verticalScrollPosition to the range |
| // 0 through maxVerticalScrollPosition. |
| // If verticalScrollBar doesn't exist, |
| // maxVerticalScrollPosition will be 0. |
| if (_verticalScrollPosition < 0) |
| { |
| _verticalScrollPosition = 0; |
| changed = true; |
| } |
| else if (_verticalScrollPosition > maxVerticalScrollPosition) |
| { |
| _verticalScrollPosition = maxVerticalScrollPosition; |
| changed = true; |
| } |
| |
| return changed; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function createContentPane():void |
| { |
| if (contentPane) |
| return; |
| |
| creatingContentPane = true; |
| |
| // Reparent the children. Get the number before we create contentPane |
| // because that changes logic of how many children we have |
| var n:int = numChildren; |
| |
| var newPane:Sprite = new FlexSprite(); |
| newPane.name = "contentPane"; |
| |
| // Place content pane above border and background image but below |
| // all other chrome. |
| var childIndex:int; |
| if (border) |
| { |
| childIndex = rawChildren.getChildIndex(DisplayObject(border)) + 1; |
| if (border is IRectangularBorder && IRectangularBorder(border).hasBackgroundImage) |
| childIndex++; |
| } |
| else |
| { |
| childIndex = 0; |
| } |
| rawChildren.addChildAt(newPane, childIndex); |
| |
| for (var i:int = 0; i < n; i++) |
| { |
| // use super because contentPane now exists and messes up getChildAt(); |
| var child:IUIComponent = |
| IUIComponent(super.getChildAt(_firstChildIndex)); |
| newPane.addChild(DisplayObject(child)); |
| child.parentChanged(newPane); |
| _numChildren--; // required |
| } |
| |
| contentPane = newPane; |
| |
| creatingContentPane = false |
| |
| // UIComponent sets $visible to false. If we don't make it true here, |
| // nothing shows up. Making this true should be harmless, as the |
| // container itself should be false, and so should all its children. |
| contentPane.visible = true; |
| } |
| |
| /** |
| * Positions the container's content area relative to the viewable area |
| * based on the horizontalScrollPosition and verticalScrollPosition properties. |
| * Content that doesn't appear in the viewable area gets clipped. |
| * This method should be overridden by subclasses that have scrollable |
| * chrome in the content area. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function scrollChildren():void |
| { |
| if (!contentPane) |
| return; |
| |
| var vm:EdgeMetrics = viewMetrics; |
| |
| var x:Number = 0; |
| var y:Number = 0; |
| var w:Number = unscaledWidth - vm.left - vm.right; |
| var h:Number = unscaledHeight - vm.top - vm.bottom; |
| |
| if (_clipContent) |
| { |
| x += _horizontalScrollPosition; |
| |
| y += _verticalScrollPosition; |
| } |
| else |
| { |
| w = scrollableWidth; |
| h = scrollableHeight; |
| } |
| |
| // If we have enough space to display everything, don't set |
| // scrollRect. |
| var sr:Rectangle = getScrollableRect(); |
| if (x == 0 && y == 0 // Not scrolled |
| && w >= sr.right && h >= sr.bottom && // Vertical content visible |
| sr.left >= 0 && sr.top >= 0 && _forceClippingCount <= 0) // No negative coordinates |
| { |
| contentPane.scrollRect = null; |
| contentPane.opaqueBackground = null; |
| contentPane.cacheAsBitmap = false; |
| } |
| else |
| { |
| contentPane.scrollRect = new Rectangle(x, y, w, h); |
| } |
| |
| if (focusPane) |
| focusPane.scrollRect = contentPane.scrollRect; |
| |
| if (border && border is IRectangularBorder && |
| IRectangularBorder(border).hasBackgroundImage) |
| { |
| IRectangularBorder(border).layoutBackgroundImage(); |
| } |
| } |
| |
| /** |
| * @private |
| * Used by a child component to force clipping during a Move effect |
| */ |
| private var _forceClippingCount:int; |
| |
| mx_internal function set forceClipping(value:Boolean):void |
| { |
| if (_clipContent) // Can only force clipping if clipContent == true |
| { |
| if (value) |
| _forceClippingCount++ |
| else |
| _forceClippingCount--; |
| |
| createContentPane(); |
| scrollChildren(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Binding |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Executes the bindings into this Container's child UIComponent objects. |
| * Flex calls this method automatically once a Container has been created. |
| * |
| * @param recurse If <code>false</code>, then only execute the bindings |
| * on the immediate children of this Container. |
| * If <code>true</code>, then also execute the bindings on this |
| * container's grandchildren, |
| * great-grandchildren, and so on. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function executeChildBindings(recurse:Boolean):void |
| { |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| if (child is IDeferredInstantiationUIComponent) |
| { |
| IDeferredInstantiationUIComponent(child). |
| executeBindings(recurse); |
| } |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function keyDownHandler(event:KeyboardEvent):void |
| { |
| // If a text field currently has focus, it is handling all arrow keys. |
| // We shouldn't also scroll this Container. |
| var focusObj:Object = getFocus(); |
| if ((focusObj is TextField) || |
| (richEditableTextClass && focusObj is richEditableTextClass)) |
| { |
| return; |
| } |
| |
| // If the KeyBoardEvent can be canceled and a descendant has done so, |
| // don't process it at all. |
| if (event.isDefaultPrevented()) |
| return; |
| |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * This method copied verbatim from mx.core.ScrollControlBase. |
| */ |
| private function mouseWheelHandler(event:MouseEvent):void |
| { |
| // If this Container has a vertical scrollbar, then handle the event |
| // and prevent further bubbling |
| } |
| |
| /** |
| * @private |
| * This function is called when the LayoutManager finishes running. |
| * Clear the forceLayout flag that was set earlier. |
| */ |
| private function layoutCompleteHandler(event:FlexEvent):void |
| { |
| UIComponentGlobals.layoutManager.removeEventListener( |
| FlexEvent.UPDATE_COMPLETE, layoutCompleteHandler); |
| forceLayout = false; |
| |
| var needToScrollChildren:Boolean = false; |
| |
| if (!isNaN(horizontalScrollPositionPending)) |
| { |
| if (horizontalScrollPositionPending < 0) |
| horizontalScrollPositionPending = 0; |
| else if (horizontalScrollPositionPending > maxHorizontalScrollPosition) |
| horizontalScrollPositionPending = maxHorizontalScrollPosition; |
| |
| horizontalScrollPositionPending = NaN; |
| } |
| |
| if (!isNaN(verticalScrollPositionPending)) |
| { |
| // Clamp verticalScrollPosition to the range 0 through maxVerticalScrollPosition. |
| // If verticalScrollBar doesn't exist, maxVerticalScrollPosition will be 0. |
| if (verticalScrollPositionPending < 0) |
| verticalScrollPositionPending = 0; |
| else if (verticalScrollPositionPending > maxVerticalScrollPosition) |
| verticalScrollPositionPending = maxVerticalScrollPosition; |
| |
| verticalScrollPositionPending = NaN; |
| } |
| |
| if (needToScrollChildren) |
| scrollChildren(); |
| } |
| |
| /** |
| * @private |
| */ |
| private function creationCompleteHandler(event:FlexEvent):void |
| { |
| numChildrenCreated--; |
| if (numChildrenCreated <= 0) |
| dispatchEvent(new FlexEvent("childrenCreationComplete")); |
| } |
| |
| /** |
| * @private |
| */ |
| private function blocker_clickHandler(event:Event):void |
| { |
| // Swallow click events from blocker. |
| event.stopPropagation(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function measure():void |
| { |
| super.measure(); |
| |
| var preferredWidth:Number; |
| var preferredHeight:Number; |
| var minWidth:Number; |
| var minHeight:Number; |
| |
| // Determine the size of each tile cell and cache the values |
| // in cellWidth and cellHeight for later use by updateDisplayList(). |
| findCellSize(); |
| |
| // Min width and min height are large enough to display a single child. |
| minWidth = cellWidth; |
| minHeight = cellHeight; |
| |
| // Determine the width and height necessary to display the tiles |
| // in an N-by-N grid (with number of rows equal to number of columns). |
| var n:int = numChildren; |
| |
| // Don't count children that don't need their own layout space. |
| var temp:int = n; |
| for (var i:int = 0; i < n; i++) |
| { |
| if (!IUIComponent(getChildAt(i)).includeInLayout) |
| temp--; |
| } |
| n = temp; |
| |
| if (n > 0) |
| { |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| var verticalGap:Number = getStyle("verticalGap"); |
| |
| var majorAxis:Number; |
| |
| // If an explicit dimension or flex is set for the majorAxis, |
| // set as many children as possible along the axis. |
| if (direction == "horizontal") |
| { |
| var unscaledExplicitWidth:Number = explicitWidth / Math.abs(scaleX); |
| if (!isNaN(unscaledExplicitWidth)) |
| { |
| // If we have an explicit height set, |
| // see how many children can fit in the given height: |
| // majorAxis * (cellWidth + horizontalGap) - horizontalGap == unscaledExplicitWidth |
| majorAxis = Math.floor((unscaledExplicitWidth + horizontalGap) / |
| (cellWidth + horizontalGap)); |
| } |
| } |
| else |
| { |
| var unscaledExplicitHeight:Number = explicitHeight / Math.abs(scaleY); |
| if (!isNaN(unscaledExplicitHeight)) |
| { |
| // If we have an explicit height set, |
| // see how many children can fit in the given height: |
| // majorAxis * (cellHeight + verticalGap) - verticalGap == unscaledExplicitHeight |
| majorAxis = Math.floor((unscaledExplicitHeight + verticalGap) / |
| (cellHeight + verticalGap)); |
| } |
| } |
| |
| // Finally, if majorAxis still isn't defined, use the |
| // square root of the number of children. |
| if (isNaN(majorAxis)) |
| majorAxis = Math.ceil(Math.sqrt(n)); |
| |
| // Even if there's not room, force at least one cell |
| // on each row/column. |
| if (majorAxis < 1) |
| majorAxis = 1; |
| |
| var minorAxis:Number = Math.ceil(n / majorAxis); |
| |
| if (direction == "horizontal") |
| { |
| preferredWidth = majorAxis * cellWidth + |
| (majorAxis - 1) * horizontalGap; |
| |
| preferredHeight = minorAxis * cellHeight + |
| (minorAxis - 1) * verticalGap; |
| } |
| else |
| { |
| preferredWidth = minorAxis * cellWidth + |
| (minorAxis - 1) * horizontalGap; |
| |
| preferredHeight = majorAxis * cellHeight + |
| (majorAxis - 1) * verticalGap; |
| } |
| } |
| else |
| { |
| preferredWidth = minWidth; |
| preferredHeight = minHeight; |
| } |
| |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| var hPadding:Number = vm.left + vm.right; |
| var vPadding:Number = vm.top + vm.bottom; |
| |
| // Add padding for margins and borders. |
| minWidth += hPadding; |
| preferredWidth += hPadding; |
| minHeight += vPadding; |
| preferredHeight += vPadding; |
| |
| measuredMinWidth = Math.ceil(minWidth); |
| measuredMinHeight = Math.ceil(minHeight); |
| measuredWidth = Math.ceil(preferredWidth); |
| measuredHeight = Math.ceil(preferredHeight); |
| |
| |
| var colCount:int; |
| |
| // Determine the size of each tile cell |
| findCellSize(); |
| |
| // Min width and min height are large enough to display a single child |
| minWidth = cellWidth; |
| minHeight = cellHeight; |
| |
| // Determine the width and height necessary to display the tiles in an |
| // N-by-N grid (with number of rows equal to number of columns). |
| var numChildren:int = this.numChildren; |
| if (numChildren > 0) |
| { |
| horizontalGap = getStyle("horizontalGap"); |
| verticalGap = getStyle("verticalGap"); |
| var columns:Array /* of Number */; |
| vm = viewMetricsAndPadding; |
| var rowCount:int; |
| |
| // If an explicit dimension or flex is set for the majorAxis, |
| // set as many children as possible along the axis. |
| if (direction == "vertical") |
| { |
| var bCalcColumns:Boolean = false; |
| |
| if (!isNaN(explicitHeight)) |
| { |
| preferredHeight = explicitHeight - vm.top - vm.bottom; |
| bCalcColumns = true; |
| } |
| else if (!isNaN(_actualMajorAxisLength)) |
| { |
| preferredHeight = _actualMajorAxisLength * cellHeight + |
| (_actualMajorAxisLength - 1) * verticalGap; |
| _actualMajorAxisLength = NaN; |
| bCalcColumns = true; |
| } |
| |
| if (bCalcColumns) |
| { |
| columns = calcColumnWidthsForHeight(preferredHeight); |
| preferredWidth = 0; |
| colCount = columns.length; |
| n = colCount; |
| for (i = 0; i < n; i++) |
| { |
| preferredWidth += columns[i]; |
| } |
| preferredWidth += (colCount - 1) * horizontalGap; |
| |
| rowCount = Math.min(numChildren, |
| Math.max(1, Math.floor( |
| (preferredHeight + verticalGap) / |
| (cellHeight + verticalGap)))); |
| preferredHeight = rowCount * cellHeight + |
| (rowCount - 1) * verticalGap; |
| _preferredMajorAxisLength = rowCount; |
| } |
| else |
| { |
| // If we have flex, |
| // our majorAxis can contain all our children |
| preferredHeight = numChildren * cellHeight + |
| (numChildren - 1) * verticalGap; |
| preferredWidth = cellWidth; |
| _preferredMajorAxisLength = numChildren; |
| } |
| } |
| else |
| { |
| if (!isNaN(explicitWidth)) |
| { |
| // If we have an explicit height set, |
| // see how many children can fit in the given height. |
| preferredWidth = explicitWidth - vm.left - vm.right; |
| } |
| else if (!isNaN(_actualMajorAxisLength)) |
| { |
| preferredWidth = _actualMajorAxisLength - vm.left - vm.right; |
| _actualMajorAxisLength = NaN; |
| } |
| else |
| { |
| preferredWidth = screen.width - vm.left - vm.right; |
| } |
| |
| columns = calcColumnWidthsForWidth(preferredWidth); |
| preferredWidth = 0; |
| colCount = columns.length; |
| n = colCount; |
| for (i = 0; i < n; i++) |
| { |
| preferredWidth += columns[i]; |
| } |
| |
| preferredWidth += (colCount - 1) * horizontalGap; |
| rowCount = Math.ceil(numChildren / colCount); |
| preferredHeight = rowCount * cellHeight + |
| (rowCount - 1) * verticalGap; |
| _preferredMajorAxisLength = colCount; |
| } |
| |
| } |
| else |
| { |
| preferredWidth = minWidth; |
| preferredHeight = minHeight; |
| } |
| |
| // Add extra for borders and margins. |
| vm = viewMetricsAndPadding; |
| var hExtra:Number = vm.left + vm.right; |
| var vExtra:Number = vm.top + vm.bottom; |
| minWidth += hExtra; |
| preferredWidth += hExtra; |
| minHeight += vExtra; |
| preferredHeight += vExtra; |
| |
| measuredMinWidth = minWidth; |
| measuredMinHeight = minHeight; |
| measuredWidth = preferredWidth; |
| measuredHeight = preferredHeight; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Calculate and store the cellWidth and cellHeight. |
| */ |
| mx_internal function findCellSize():void |
| { |
| // If user explicitly supplied both a tileWidth and |
| // a tileHeight, then use those values. |
| var widthSpecified:Boolean = !isNaN(tileWidth); |
| var heightSpecified:Boolean = !isNaN(tileHeight); |
| if (widthSpecified && heightSpecified) |
| { |
| cellWidth = tileWidth; |
| cellHeight = tileHeight; |
| return; |
| } |
| |
| // Reset the max child width and height |
| var maxChildWidth:Number = 0; |
| var maxChildHeight:Number = 0; |
| |
| // Loop over the children to find the max child width and height. |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IUIComponent = getLayoutChildAt(i); |
| |
| if (!child.includeInLayout) |
| continue; |
| |
| var width:Number = child.getExplicitOrMeasuredWidth(); |
| if (width > maxChildWidth) |
| maxChildWidth = width; |
| |
| var height:Number = child.getExplicitOrMeasuredHeight(); |
| if (height > maxChildHeight) |
| maxChildHeight = height; |
| } |
| |
| // If user explicitly specified either width or height, use the |
| // user-supplied value instead of the one we computed. |
| cellWidth = widthSpecified ? tileWidth : maxChildWidth; |
| cellHeight = heightSpecified ? tileHeight : maxChildHeight; |
| } |
| |
| /** |
| * @private |
| * Assigns the actual size of the specified child, |
| * based on its measurement properties and the cell size. |
| */ |
| private function setChildSize(child:IUIComponent):void |
| { |
| var childWidth:Number; |
| var childHeight:Number; |
| var childPref:Number; |
| var childMin:Number; |
| |
| if (child.percentWidth > 0) |
| { |
| // Set child width to be a percentage of the size of the cell. |
| childWidth = Math.min(cellWidth, |
| cellWidth * child.percentWidth / 100); |
| } |
| else |
| { |
| // The child is not flexible, so set it to its preferred width. |
| childWidth = child.getExplicitOrMeasuredWidth(); |
| |
| // If an explicit tileWidth has been set on this Tile, |
| // then the child may extend outside the bounds of the tile cell. |
| // In that case, we'll honor the child's width or minWidth, |
| // but only if those values were explicitly set by the developer, |
| // not if they were implicitly set based on measurements. |
| if (childWidth > cellWidth) |
| { |
| childPref = isNaN(child.explicitWidth) ? |
| 0 : |
| child.explicitWidth; |
| |
| childMin = isNaN(child.explicitMinWidth) ? |
| 0 : |
| child.explicitMinWidth; |
| |
| childWidth = (childPref > cellWidth || |
| childMin > cellWidth) ? |
| Math.max(childMin, childPref) : |
| cellWidth; |
| } |
| } |
| |
| if (child.percentHeight > 0) |
| { |
| childHeight = Math.min(cellHeight, |
| cellHeight * child.percentHeight / 100); |
| } |
| else |
| { |
| childHeight = child.getExplicitOrMeasuredHeight(); |
| |
| if (childHeight > cellHeight) |
| { |
| childPref = isNaN(child.explicitHeight) ? |
| 0 : |
| child.explicitHeight; |
| |
| childMin = isNaN(child.explicitMinHeight) ? |
| 0 : |
| child.explicitMinHeight; |
| |
| childHeight = (childPref > cellHeight || |
| childMin > cellHeight) ? |
| Math.max(childMin, childPref) : |
| cellHeight; |
| } |
| } |
| |
| child.setActualSize(childWidth, childHeight); |
| } |
| |
| /** |
| * @private |
| * Compute how much adjustment must occur in the x direction |
| * in order to align a component of a given width into the cell. |
| */ |
| mx_internal function calcHorizontalOffset(width:Number, |
| horizontalAlign:String):Number |
| { |
| var xOffset:Number; |
| |
| if (horizontalAlign == "left") |
| xOffset = 0; |
| |
| else if (horizontalAlign == "center") |
| xOffset = (cellWidth - width) / 2; |
| |
| else if (horizontalAlign == "right") |
| xOffset = (cellWidth - width); |
| |
| return xOffset; |
| } |
| |
| /** |
| * @private |
| * Compute how much adjustment must occur in the y direction |
| * in order to align a component of a given height into the cell. |
| */ |
| mx_internal function calcVerticalOffset(height:Number, |
| verticalAlign:String):Number |
| { |
| var yOffset:Number; |
| |
| if (verticalAlign == "top") |
| yOffset = 0; |
| |
| else if (verticalAlign == "middle") |
| yOffset = (cellHeight - height) / 2; |
| |
| else if (verticalAlign == "bottom") |
| yOffset = (cellHeight - height); |
| |
| return yOffset; |
| } |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function addLegendItem(legendData:Object):void |
| { |
| var c:Class = legendItemClass; |
| var newItem:LegendItem = new c(); |
| |
| if (legendData.label != "") |
| newItem.label = legendData.label; |
| |
| if (legendData.element) |
| newItem.element = legendData.element; |
| |
| if ("fill" in legendData) |
| newItem.setStyle("fill",legendData["fill"]); |
| |
| newItem.markerAspectRatio = legendData.aspectRatio; |
| newItem.legendData = legendData; |
| newItem.percentWidth = 100; |
| newItem.percentHeight = 100; |
| |
| addChild(newItem); |
| |
| newItem.marker = legendData.marker; |
| |
| newItem.setStyle("backgroundColor", 0xEEEEFF); |
| } |
| |
| /** |
| * @private |
| */ |
| private function populateFromArray(dp:Object):void |
| { |
| if (dp is ChartBase) |
| dp = dp.legendData; |
| |
| removeAllChildren(); |
| |
| var curItem:Object; |
| var n:int = dp.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| var curList:Array /* of LegendData */ = (dp[i] as Array); |
| if (!curList) |
| { |
| curItem = dp[i]; |
| addLegendItem(curItem); |
| } |
| else |
| { |
| var m:int = curList.length; |
| for (var j:int = 0; j < m; j++) |
| { |
| curItem = curList[j]; |
| addLegendItem(curItem); |
| } |
| } |
| } |
| |
| _actualMajorAxisLength = NaN; |
| } |
| |
| /** |
| * @private |
| * Returns a numeric value for the align setting. |
| * 0 = left/top, 0.5 = center, 1 = right/bottom |
| */ |
| private function findHorizontalAlignValue():Number |
| { |
| var horizontalAlign:String = getStyle("horizontalAlign"); |
| |
| if (horizontalAlign == "center") |
| return 0.5; |
| |
| else if (horizontalAlign == "right") |
| return 1; |
| |
| // default = left |
| return 0; |
| } |
| |
| /** |
| * @private |
| * Returns a numeric value for the align setting. |
| * 0 = left/top, 0.5 = center, 1 = right/bottom |
| */ |
| private function findVerticalAlignValue():Number |
| { |
| var verticalAlign:String = getStyle("verticalAlign"); |
| |
| if (verticalAlign == "middle") |
| return 0.5; |
| |
| else if (verticalAlign == "bottom") |
| return 1; |
| |
| // default = top |
| return 0; |
| } |
| |
| /** |
| * @private |
| */ |
| private function widthPadding(numChildren:Number):Number |
| { |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| var padding:Number = vm.left + vm.right; |
| |
| if (numChildren > 1 && direction == "horizontal") |
| padding += getStyle("horizontalGap") * (numChildren - 1); |
| |
| return padding; |
| } |
| |
| /** |
| * @private |
| */ |
| private function heightPadding(numChildren:Number):Number |
| { |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| var padding:Number = vm.top + vm.bottom; |
| |
| if (numChildren > 1 && direction == "vertical") |
| padding += getStyle("verticalGap") * (numChildren - 1); |
| |
| return padding; |
| } |
| |
| /** |
| * @private |
| */ |
| private function calcColumnWidthsForHeight(h:Number):Array /* of Number */ |
| { |
| var n:Number = numChildren; |
| |
| var verticalGap:Number = getStyle("verticalGap"); |
| if (isNaN(verticalGap)) |
| verticalGap = 0; |
| |
| var rowCount:int = Math.min(n, Math.max( |
| 1, Math.floor((h + verticalGap) / (cellHeight + verticalGap)))); |
| |
| var nColumns:int = rowCount == 0 ? 0: Math.ceil(n / rowCount); |
| |
| var columnSizes:Array /* of Number */; |
| if (nColumns <= 1) |
| { |
| columnSizes = [cellWidth]; |
| } |
| else |
| { |
| columnSizes = []; |
| for (var i:int = 0; i < nColumns; i++) |
| { |
| columnSizes[i] = 0; |
| } |
| |
| for (i = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| var col:int = Math.floor(i / rowCount); |
| columnSizes[col] = Math.max(columnSizes[col], |
| child.getExplicitOrMeasuredWidth()); |
| } |
| } |
| |
| return columnSizes; |
| } |
| |
| /** |
| * @private |
| * Bound the layout in the vertical direction |
| * and let it grow horizontally. |
| */ |
| private function layoutVertical():void |
| { |
| var n:Number = numChildren; |
| |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| var verticalGap:Number = getStyle("verticalGap"); |
| |
| var horizontalAlign:String = getStyle("horizontalAlign"); |
| var verticalAlign:String = getStyle("verticalAlign"); |
| |
| var xPos:Number = vm.left; |
| var yPos:Number = vm.top; |
| var yEnd:Number = unscaledHeight - vm.bottom; |
| |
| var rowCount:int = Math.min(n, Math.max(1, Math.floor( |
| (yEnd - yPos + verticalGap) / (cellHeight + verticalGap)))); |
| |
| var columnSizes:Array /* of Number */ = []; |
| |
| columnSizes = calcColumnWidthsForHeight(yEnd - yPos); |
| var nColumns:int = columnSizes.length; |
| |
| for (var i:Number = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| |
| var col:int = Math.floor(i / rowCount); |
| var colWidth:Number = columnSizes[col]; |
| |
| var childWidth:Number; |
| var childHeight:Number; |
| |
| if (child.percentWidth > 0) |
| { |
| childWidth = Math.min(colWidth, |
| colWidth * child.percentWidth / 100); |
| } |
| else |
| { |
| childWidth = child.getExplicitOrMeasuredWidth(); |
| } |
| |
| if (child.percentHeight > 0) |
| { |
| childHeight = Math.min(cellHeight, |
| cellHeight * child.percentHeight / 100); |
| } |
| else |
| { |
| childHeight = child.getExplicitOrMeasuredHeight(); |
| } |
| |
| child.setActualSize(childWidth, childHeight); |
| |
| // Align the child in the cell. |
| var xOffset:Number = |
| Math.floor(calcHorizontalOffset(child.width, horizontalAlign)); |
| var yOffset:Number = |
| Math.floor(calcVerticalOffset(child.height, verticalAlign)); |
| child.move(xPos + xOffset, yPos + yOffset); |
| |
| if ((i % rowCount) == rowCount - 1) |
| { |
| yPos = vm.top; |
| xPos += (colWidth + horizontalGap); |
| } |
| else |
| { |
| yPos += (cellHeight + verticalGap); |
| } |
| } |
| |
| if (rowCount != _preferredMajorAxisLength) |
| { |
| _actualMajorAxisLength = rowCount; |
| invalidateSize(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function calcColumnWidthsForWidth(w:Number):Array /* of Number */ |
| { |
| var n:Number = numChildren; |
| |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| |
| var xPos:Number = 0; |
| var xEnd:Number = w; |
| |
| // first determine the max number of columns we can have; |
| var nColumns:int = 0; |
| var columnSizes:Array /* of Number */; |
| |
| for (var i:Number = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| var childPreferredWidth:Number = child.getExplicitOrMeasuredWidth(); |
| |
| // start a new row? |
| if (xPos + childPreferredWidth > xEnd) |
| { |
| break; |
| } |
| xPos += (childPreferredWidth + horizontalGap); |
| |
| nColumns++; |
| } |
| |
| var columnsTooWide:Boolean = true; |
| |
| while (nColumns > 1 && columnsTooWide) |
| { |
| columnSizes = []; |
| for (i = 0; i < nColumns; i++) |
| { |
| columnSizes[i] = 0; |
| } |
| for (i = 0; i < n; i++) |
| { |
| var col:int = i % nColumns; |
| columnSizes[col] = Math.max(columnSizes[col], |
| IUIComponent(getChildAt(i)).getExplicitOrMeasuredWidth()); |
| } |
| xPos = 0; |
| |
| for (i = 0; i < nColumns; i++) |
| { |
| if (xPos + columnSizes[i] > xEnd) |
| break; |
| xPos += columnSizes[i] + horizontalGap; |
| } |
| if (i == nColumns) |
| columnsTooWide = false; |
| else |
| nColumns--; |
| } |
| |
| if (nColumns <= 1) |
| { |
| nColumns = 1; |
| columnSizes = [cellWidth]; |
| } |
| |
| return columnSizes; |
| } |
| |
| /** |
| * @private |
| */ |
| private function layoutHorizontal():void |
| { |
| var n:Number = numChildren; |
| |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| var verticalGap:Number = getStyle("verticalGap") |
| |
| var horizontalAlign:String = getStyle("horizontalAlign"); |
| var verticalAlign:String = getStyle("verticalAlign"); |
| |
| var xPos:Number = vm.left; |
| var xEnd:Number = _unscaledWidth - vm.right; |
| var yPos:Number = vm.top; |
| |
| // First determine the max number of columns we can have. |
| var nColumns:int = 0; |
| var columnSizes:Array /* of Number */; |
| |
| columnSizes = calcColumnWidthsForWidth(xEnd - xPos); |
| nColumns = columnSizes.length; |
| |
| for (var i:Number = 0; i < n; i++) |
| { |
| var child:IUIComponent = IUIComponent(getChildAt(i)); |
| |
| var col:int = i % nColumns; |
| var colWidth:Number = columnSizes[col]; |
| |
| var childWidth:Number; |
| var childHeight:Number; |
| |
| if (child.percentWidth > 0) |
| { |
| childWidth = Math.min(colWidth, |
| colWidth * child.percentWidth / 100); |
| } |
| else |
| { |
| childWidth = child.getExplicitOrMeasuredWidth(); |
| } |
| |
| if (child.percentHeight > 0) |
| { |
| childHeight = Math.min(cellHeight, |
| cellHeight * child.percentHeight / 100); |
| } |
| else |
| { |
| childHeight = child.getExplicitOrMeasuredHeight(); |
| } |
| |
| child.setActualSize(childWidth, childHeight); |
| |
| // Align the child in the cell. |
| var xOffset:Number = |
| Math.floor(calcHorizontalOffset(child.width, horizontalAlign)); |
| var yOffset:Number = |
| Math.floor(calcVerticalOffset(child.height, verticalAlign)); |
| child.move(xPos + xOffset, yPos + yOffset); |
| |
| if (col == nColumns - 1) |
| { |
| xPos = vm.left; |
| yPos += (cellHeight + verticalGap); |
| } |
| else |
| { |
| xPos += (columnSizes[col] + horizontalGap); |
| } |
| } |
| |
| if (nColumns != _preferredMajorAxisLength) |
| { |
| _actualMajorAxisLength = _unscaledWidth; |
| invalidateSize(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function legendDataChangedHandler(event:Event = null):void |
| { |
| invalidateProperties(); |
| invalidateSize(); |
| _childrenDirty = true;; |
| } |
| |
| /** |
| * @private |
| */ |
| private function childMouseEventHandler(event:MouseEvent):void |
| { |
| var p:DisplayObject = DisplayObject(event.target); |
| |
| while (p != this && p.parent != this) |
| { |
| p = p.parent; |
| } |
| |
| if (p is LegendItem) |
| dispatchEvent(new LegendMouseEvent(event.type, event, LegendItem(p))); |
| } |
| } |
| } |
| |
| |
| import flash.display.DisplayObject; |
| import flash.geom.Point; |
| |
| import mx.charts.Legend; |
| import mx.core.IChildList; |
| import mx.core.mx_internal; |
| |
| use namespace mx_internal; |
| /** |
| * @private |
| * Helper class for the rawChildren property of the Container class. |
| * For descriptions of the properties and methods, |
| * see the IChildList interface. |
| * |
| * @see mx.core.Container |
| */ |
| class LegendRawChildrenList implements IChildList |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Notes |
| // |
| //-------------------------------------------------------------------------- |
| |
| /* |
| |
| Although at the level of a Flash DisplayObjectContainer, all |
| children are equal, in a Flex Container some children are "more |
| equal than others". (George Orwell, "Animal Farm") |
| |
| In particular, Flex distinguishes between content children and |
| non-content (or "chrome") children. Content children are the kind |
| that can be specified in MXML. If you put several controls |
| into a VBox, those are its content children. Non-content children |
| are the other ones that you get automatically, such as a |
| background/border, scrollbars, the titlebar of a Panel, |
| AccordionHeaders, etc. |
| |
| Most application developers are uninterested in non-content children, |
| so Container overrides APIs such as numChildren and getChildAt() |
| to deal only with content children. For example, Container, keeps |
| its own _numChildren counter. |
| |
| However, developers of custom containers need to be able to deal |
| with both content and non-content children, so they require similar |
| APIs that operate on all children. |
| |
| For the public API, it would be ugly to have double APIs on Container |
| such as getChildAt() and all_getChildAt(). Instead, Container has |
| a public rawChildren property which lets you access APIs which |
| operate on all the children, in the same way that the |
| DisplayObjectContainer APIs do. For example, getChildAt(0) returns |
| the first content child, while rawChildren.getChildAt(0) returns |
| the first child (either content or non-content). |
| |
| This ContainerRawChildrenList class implements the rawChildren |
| property. Note that it simply calls a second set of parallel |
| mx_internal APIs in Container. (They're named, for example, |
| _getChildAt() instead of all_getChildAt()). |
| |
| Many of the all-children APIs in Container such as _getChildAt() |
| simply call super.getChildAt() in order to get the implementation |
| in DisplayObjectContainer. It would be nice if we could eliminate |
| _getChildAt() in Container and simply implement the all-children |
| version in this class by calling the DisplayObjectContainer method. |
| But once Container overrides getChildAt(), there is no way |
| to call the supermethod through an instance. |
| |
| */ |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Constructor. |
| */ |
| public function LegendRawChildrenList(owner:Legend) |
| { |
| super(); |
| |
| this.owner = owner; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var owner:Legend; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // numChildren |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get numChildren():int |
| { |
| return owner.$numChildren; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function addChild(child:DisplayObject):DisplayObject |
| { |
| return owner.rawChildren_addChild(child); |
| } |
| |
| /** |
| * @private |
| */ |
| public function addChildAt(child:DisplayObject, index:int):DisplayObject |
| { |
| return owner.rawChildren_addChildAt(child, index); |
| } |
| |
| /** |
| * @private |
| */ |
| public function removeChild(child:DisplayObject):DisplayObject |
| { |
| return owner.rawChildren_removeChild(child); |
| } |
| |
| /** |
| * @private |
| */ |
| public function removeChildAt(index:int):DisplayObject |
| { |
| return owner.rawChildren_removeChildAt(index); |
| } |
| |
| /** |
| * @private |
| */ |
| public function getChildAt(index:int):DisplayObject |
| { |
| return owner.rawChildren_getChildAt(index); |
| } |
| |
| /** |
| * @private |
| */ |
| public function getChildByName(name:String):DisplayObject |
| { |
| return owner.rawChildren_getChildByName(name); |
| } |
| |
| /** |
| * @private |
| */ |
| public function getChildIndex(child:DisplayObject):int |
| { |
| return owner.rawChildren_getChildIndex(child); |
| } |
| |
| /** |
| * @private |
| */ |
| public function setChildIndex(child:DisplayObject, newIndex:int):void |
| { |
| owner.rawChildren_setChildIndex(child, newIndex); |
| } |
| |
| /** |
| * @private |
| */ |
| public function getObjectsUnderPoint(point:Point):Array |
| { |
| return owner.rawChildren_getObjectsUnderPoint(point); |
| } |
| |
| /** |
| * @private |
| */ |
| public function contains(child:DisplayObject):Boolean |
| { |
| return owner.rawChildren_contains(child); |
| } |
| } |