| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package spark.components.supportClasses |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.Sprite; |
| import flash.events.Event; |
| import flash.events.GestureEvent; |
| import flash.events.MouseEvent; |
| import flash.events.PressAndTapGestureEvent; |
| import flash.events.TouchEvent; |
| import flash.events.TransformGestureEvent; |
| import flash.filters.ShaderFilter; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| |
| import mx.core.ILayoutElement; |
| import mx.core.IVisualElement; |
| import mx.core.UIComponent; |
| import mx.core.UIComponentGlobals; |
| import mx.core.mx_internal; |
| import mx.events.PropertyChangeEvent; |
| import mx.graphics.shaderClasses.LuminosityMaskShader; |
| |
| import spark.components.ResizeMode; |
| import spark.core.IViewport; |
| import spark.core.MaskType; |
| import spark.events.DisplayLayerObjectExistenceEvent; |
| import spark.layouts.BasicLayout; |
| import spark.layouts.supportClasses.LayoutBase; |
| import spark.utils.FTETextUtil; |
| import spark.utils.MaskUtil; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| include "../../styles/metadata/BasicInheritingTextStyles.as" |
| include "../../styles/metadata/AdvancedInheritingTextStyles.as" |
| include "../../styles/metadata/SelectionFormatTextStyles.as" |
| |
| /** |
| * 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, mobile")] |
| |
| /** |
| * The colors to use for the backgrounds of the items in the list. |
| * The value is an array of one or more colors. |
| * The backgrounds of the list items alternate among the colors in the array. |
| * |
| * <p>The default value for the Spark theme is <code>undefined</code>. |
| * The default value for the Mobile theme is <code>0xFFFFFF</code>.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="alternatingItemColors", type="Array", arrayType="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * The main color for a component. |
| * |
| * @default 0xCCCCCC |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="chromeColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * The alpha of the content background for this component. |
| * |
| * @default 1.0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="contentBackgroundAlpha", type="Number", inherit="yes", theme="spark, mobile", minValue="0.0", maxValue="1.0")] |
| |
| /** |
| * The color of the content background for this component. |
| * |
| * <p>For a List, changing <code>contentBackgroundColor</code> will |
| * change the content background color of the List; however, if the item renderer |
| * is opaque, the user may not see any difference. The item renderer's color is |
| * affected by <code>alternatingItemColors</code>. In the Spark theme, by default, item |
| * renderers are transparent (<code>alternatingItemColors = undefined</code>); however, |
| * in the Mobile theme, item renderers are opaque by default |
| * (<code>alternatingItemColors = 0xFFFFFF</code>).</p> |
| * |
| * <p>The default value for the Spark theme is <code>0xFFFFFF</code>. |
| * The default value for the Mobile theme is <code>0xF0F0F0</code>.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="contentBackgroundColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * The alpha value when the container is disabled. |
| * |
| * @default 0.5 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="disabledAlpha", type="Number", inherit="no", theme="spark, mobile", minValue="0.0", maxValue="1.0")] |
| |
| /** |
| * Color of the background of an item renderer when it is being pressed down |
| * |
| * <p>If <code>downColor</code> is set to <code>undefined</code>, |
| * <code>downColor</code> is not used.</p> |
| * |
| * <p>The default value for the Spark theme is <code>undefined</code>. |
| * The default value for the Mobile theme is <code>0xE0E0E0</code>.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10.1 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="downColor", type="uint", format="Color", inherit="yes", theme="mobile")] |
| |
| /** |
| * 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, mobile")] |
| |
| /** |
| * Color of the highlights when the mouse is over the component. |
| * |
| * <p>This style is only applicable in mouse <code>interactionMode</code>.</p> |
| * |
| * @default 0xCEDBEF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="rollOverColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * Color of any symbol of a component. Examples include the check mark of a CheckBox or |
| * the arrow of a scroll 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, mobile")] |
| |
| /** |
| * When in touch interaction mode, the number of milliseconds to wait after the user |
| * interaction has occured before showing the component in a visually down state. |
| * |
| * <p>The reason for this delay is because when a user initiates a scroll gesture, we don't want |
| * components to flicker as they touch the screen. By having a reasonable delay, we make |
| * sure that the user still gets feedback when they press down on a component, but that the |
| * feedback doesn't come too quickly that it gets displayed during a scroll gesture |
| * operation.</p> |
| * |
| * <p>If the mobile theme is applied, the default value for this style is 100 ms for |
| * components inside of a Scroller and 0 ms for components outside of a Scroller.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10.1 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="touchDelay", type="Number", format="Time", inherit="yes", minValue="0.0")] |
| |
| //-------------------------------------- |
| // Excluded APIs |
| //-------------------------------------- |
| |
| [Exclude(name="focusBlendMode", kind="style")] |
| [Exclude(name="focusThickness", kind="style")] |
| |
| /** |
| * The GroupBase class defines the base class for components that display visual elements. |
| * A group component does not control the layout of the visual items that it contains. |
| * Instead, the layout is handled by a separate layout component. |
| * |
| * @mxml |
| * |
| * <p>The <code><s:GroupBase></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <s:GroupBase |
| * <strong>Properties</strong> |
| * autoLayout="true" |
| * clipAndEnableScrolling="false" |
| * horizontalScrollPosition="null" |
| * luminosityClip="false" |
| * luminosityInvert="false" |
| * layout="BasicLayout" |
| * mask="" |
| * maskType="clip" |
| * mouseEnabledWhereTransparent="true" |
| * resizeMode="noScale" |
| * verticalScrollPosition="no default" |
| * |
| * <strong>Styles</strong> |
| * accentColor="0x0099FF" |
| * alignmentBaseline="useDominantBaseline" |
| * alternatingItemColors="undefined" |
| * baselineShift="0" |
| * blockProgression="tb" |
| * breakOpportunity="auto" |
| * cffHinting="horizontalStem" |
| * chromeColor="0xCCCCCC" |
| * color="0x000000" |
| * contentBackgroundAlpha="1.0" |
| * contentBackgroundColor="0xFFFFFF" |
| * clearFloats="none" |
| * digitCase="default" |
| * digitWidth="default" |
| * direction="ltr" |
| * disabledAlpha="0.5" |
| * dominantBaseline="auto" |
| * firstBaselineOffset="auto" |
| * focusColor="0x70B2EE" |
| * focusedTextSelectionColor="A8C6EE" |
| * fontFamily="Arial" |
| * fontLookup="device" |
| * fontSize="12" |
| * fontStyle="normal" |
| * fontWeight="normal" |
| * inactiveTextSelectionColor="E8E8E8" |
| * justificationRule="auto" |
| * justificationStyle="auto" |
| * kerning="auto" |
| * leadingModel="auto" |
| * ligatureLevel="common" |
| * lineHeight="120%" |
| * lineThrough="false" |
| * listAutoPadding="40" |
| * listStylePosition="outside" |
| * listStyleType="disc" |
| * locale="en" |
| * paragraphEndIndent="0" |
| * paragraphSpaceAfter="0" |
| * paragraphSpaceBefore="0" |
| * paragraphStartIndent="0" |
| * renderingMode="cff" |
| * rollOverColor="0xCEDBEF" |
| * symbolColor="0x000000" |
| * tabStops="null" |
| * textAlign="start" |
| * textAlignLast="start" |
| * textAlpha="1" |
| * textDecoration="none" |
| * textIndent="0" |
| * textJustify="interWord" |
| * textRotation="auto" |
| * trackingLeft="0" |
| * trackingRight="0" |
| * typographicCase="default" |
| * unfocusedTextSelectionColor="0xE8E8E8" |
| * whiteSpaceCollapse="collapse" |
| * wordSpacing="100%,50%,150%" |
| * /> |
| * </pre> |
| * |
| * @see spark.layouts.supportClasses.LayoutBase |
| * @see spark.components.ResizeMode |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public class GroupBase extends UIComponent implements IViewport |
| { |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function GroupBase() |
| { |
| super(); |
| showInAutomationHierarchy = false; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // alpha |
| //---------------------------------- |
| |
| private var _explicitAlpha:Number = 1.0; |
| |
| /** |
| * @private |
| */ |
| override public function set alpha(value:Number):void |
| { |
| if (enabled) |
| super.alpha = value; |
| _explicitAlpha = value; |
| } |
| |
| //---------------------------------- |
| // baselinePosition |
| //---------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| override public function get baselinePosition():Number |
| { |
| if (!validateBaselinePosition()) |
| return NaN; |
| |
| // Unless the height is very small, the baselinePosition |
| // of a generic UIComponent is calculated as if there was |
| // a UITextField using the component's styles |
| // whose top coincides with the component's top. |
| // If the height is small, the baselinePosition is calculated |
| // as if there were text within whose ascent the component |
| // is vertically centered. |
| // At the crossover height, these two calculations |
| // produce the same result. |
| |
| return FTETextUtil.calculateFontBaseline(this, height, moduleFactory); |
| } |
| |
| //---------------------------------- |
| // mouseChildren |
| //---------------------------------- |
| |
| private var _explicitMouseChildren:Boolean = true; |
| |
| /** |
| * @private |
| */ |
| override public function set mouseChildren(value:Boolean):void |
| { |
| if (enabled) |
| super.mouseChildren = value; |
| _explicitMouseChildren = value; |
| } |
| |
| //---------------------------------- |
| // mouseEnabled |
| //---------------------------------- |
| |
| private var _explicitMouseEnabled:Boolean = true; |
| |
| /** |
| * @private |
| */ |
| override public function set mouseEnabled(value:Boolean):void |
| { |
| if (enabled) |
| super.mouseEnabled = value; |
| _explicitMouseEnabled = value; |
| } |
| |
| //---------------------------------- |
| // enabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function set enabled(value:Boolean):void |
| { |
| super.enabled = value; |
| |
| // If enabled, reset the mouseChildren, mouseEnabled to the previously |
| // set explicit value, otherwise disable mouse interaction. |
| super.mouseChildren = value ? _explicitMouseChildren : false; |
| super.mouseEnabled = value ? _explicitMouseEnabled : false; |
| |
| if (value) |
| super.alpha = _explicitAlpha; |
| else |
| { |
| var disabledAlpha:Number = getStyle("disabledAlpha"); |
| |
| if (!isNaN(disabledAlpha)) |
| super.alpha = disabledAlpha; |
| // else if it is NaN, it'll get handled in styleChanged() |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // layout |
| //---------------------------------- |
| |
| // layout is initialized in createChildren() if layout |
| // hasn't been set yet by someone else |
| private var _layout:LayoutBase; |
| private var _layoutProperties:Object = null; |
| private var layoutInvalidateSizeFlag:Boolean = false; |
| private var layoutInvalidateDisplayListFlag:Boolean = false; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The layout object for this container. |
| * This object is responsible for the measurement and layout of |
| * the visual elements in the container. |
| * |
| * @default spark.layouts.BasicLayout |
| * |
| * @see spark.layouts.supportClasses.LayoutBase |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get layout():LayoutBase |
| { |
| return _layout; |
| } |
| |
| /** |
| * @private |
| * |
| * Three properties are delegated to the layout: clipAndEnableScrolling, |
| * verticalScrollPosition, horizontalScrollPosition. |
| * If the layout is reset, we copy the properties from the old |
| * layout to the new one (we don't copy verticalScrollPosition |
| * and horizontalScrollPosition from an old layout object to a new layout |
| * object because this information might not translate correctly). |
| * If the new layout is null, then we |
| * temporarily store the delegated properties in _layoutProperties. |
| */ |
| public function set layout(value:LayoutBase):void |
| { |
| if (_layout == value) |
| return; |
| |
| if (_layout) |
| { |
| _layout.target = null; |
| _layout.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, redispatchLayoutEvent); |
| |
| if (clipAndEnableScrollingExplicitlySet) |
| { |
| // when the layout changes, we don't want to transfer over |
| // horizontalScrollPosition and verticalScrollPosition |
| _layoutProperties = {clipAndEnableScrolling: _layout.clipAndEnableScrolling}; |
| } |
| } |
| |
| _layout = value; |
| |
| if (_layout) |
| { |
| _layout.target = this; |
| _layout.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, redispatchLayoutEvent); |
| |
| if (_layoutProperties) |
| { |
| if (_layoutProperties.clipAndEnableScrolling !== undefined) |
| value.clipAndEnableScrolling = _layoutProperties.clipAndEnableScrolling; |
| |
| if (_layoutProperties.verticalScrollPosition !== undefined) |
| value.verticalScrollPosition = _layoutProperties.verticalScrollPosition; |
| |
| if (_layoutProperties.horizontalScrollPosition !== undefined) |
| value.horizontalScrollPosition = _layoutProperties.horizontalScrollPosition; |
| |
| _layoutProperties = null; |
| } |
| } |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| } |
| |
| /** |
| * @private |
| * Redispatch the bindable LayoutBase properties that we expose (that we "facade"). |
| */ |
| private function redispatchLayoutEvent(event:Event):void |
| { |
| var pce:PropertyChangeEvent = event as PropertyChangeEvent; |
| if (pce) |
| switch (pce.property) |
| { |
| case "verticalScrollPosition": |
| case "horizontalScrollPosition": |
| dispatchEvent(event); |
| break; |
| } |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPosition |
| //---------------------------------- |
| |
| [Bindable] |
| [Inspectable(minValue="0.0")] |
| |
| /** |
| * @copy spark.core.IViewport#horizontalScrollPosition |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get horizontalScrollPosition():Number |
| { |
| if (_layout) |
| { |
| return _layout.horizontalScrollPosition; |
| } |
| else if (_layoutProperties && |
| _layoutProperties.horizontalScrollPosition !== undefined) |
| { |
| return _layoutProperties.horizontalScrollPosition; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function set horizontalScrollPosition(value:Number):void |
| { |
| if (_layout) |
| { |
| _layout.horizontalScrollPosition = value; |
| } |
| else if (_layoutProperties) |
| { |
| _layoutProperties.horizontalScrollPosition = value; |
| } |
| else |
| { |
| _layoutProperties = {horizontalScrollPosition: value}; |
| } |
| } |
| |
| //---------------------------------- |
| // verticalScrollPosition |
| //---------------------------------- |
| |
| [Bindable] |
| [Inspectable(minValue="0.0")] |
| |
| /** |
| * @copy spark.core.IViewport#verticalScrollPosition |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get verticalScrollPosition():Number |
| { |
| if (_layout) |
| { |
| return _layout.verticalScrollPosition; |
| } |
| else if (_layoutProperties && |
| _layoutProperties.verticalScrollPosition !== undefined) |
| { |
| return _layoutProperties.verticalScrollPosition; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function set verticalScrollPosition(value:Number):void |
| { |
| if (_layout) |
| { |
| _layout.verticalScrollPosition = value; |
| } |
| else if (_layoutProperties) |
| { |
| _layoutProperties.verticalScrollPosition = value; |
| } |
| else |
| { |
| _layoutProperties = {verticalScrollPosition: value}; |
| } |
| } |
| |
| //---------------------------------- |
| // clipAndEnableScrolling |
| //---------------------------------- |
| |
| private var clipAndEnableScrollingExplicitlySet:Boolean = false; |
| |
| /** |
| * @copy spark.core.IViewport#clipAndEnableScrolling |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get clipAndEnableScrolling():Boolean |
| { |
| if (_layout) |
| { |
| return _layout.clipAndEnableScrolling; |
| } |
| else if (_layoutProperties && |
| _layoutProperties.clipAndEnableScrolling !== undefined) |
| { |
| return _layoutProperties.clipAndEnableScrolling; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function set clipAndEnableScrolling(value:Boolean):void |
| { |
| clipAndEnableScrollingExplicitlySet = true; |
| if (_layout) |
| { |
| _layout.clipAndEnableScrolling = value; |
| } |
| else if (_layoutProperties) |
| { |
| _layoutProperties.clipAndEnableScrolling = value; |
| } |
| else |
| { |
| _layoutProperties = {clipAndEnableScrolling: value}; |
| } |
| |
| // clipAndEnableScrolling affects measured minimum size |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // scrollRect |
| //---------------------------------- |
| |
| private var _scrollRectSet:Boolean = false; |
| |
| /** |
| * @private |
| * GroupBase workaround for a FP bug. Ignore attempts to reset the |
| * DisplayObject scrollRect property to null (its default value) if we've |
| * never set it. Similarly, don't read the DisplayObject scrollRect |
| * property if its value has not been set. |
| */ |
| override public function get scrollRect():Rectangle |
| { |
| return (!_scrollRectSet) ? null : super.scrollRect; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set scrollRect(value:Rectangle):void |
| { |
| if (!_scrollRectSet && !value) |
| return; |
| _scrollRectSet = true; |
| super.scrollRect = value; |
| } |
| |
| //---------------------------------- |
| // 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. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get autoLayout():Boolean |
| { |
| return _autoLayout; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set autoLayout(value:Boolean):void |
| { |
| if (_autoLayout == value) |
| return; |
| |
| _autoLayout = value; |
| |
| // If layout is being turned back on, trigger a layout to occur now. |
| if (value) |
| { |
| invalidateSize(); |
| invalidateDisplayList(); |
| invalidateParentSizeAndDisplayList(); |
| } |
| } |
| |
| //---------------------------------- |
| // overlay |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the overlay property |
| */ |
| mx_internal var _overlay:DisplayLayer; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The overlay plane for this group. |
| * All objects of the overlay plane render on top of the Group elements. |
| * |
| * <p><b>Note: </b>Do not retain this object because the group destroys and creates it on demand.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get overlay():DisplayLayer |
| { |
| if (!_overlay) |
| { |
| _overlay = new DisplayLayer(); |
| _overlay.addEventListener(DisplayLayerObjectExistenceEvent.OBJECT_ADD, overlay_objectAdd); |
| _overlay.addEventListener(DisplayLayerObjectExistenceEvent.OBJECT_REMOVE, overlay_objectRemove); |
| |
| // Invalidate properties, so that if nothing was actually added to the |
| // overlay object, we'll clean it up: |
| invalidateProperties(); |
| } |
| return _overlay; |
| } |
| |
| /** |
| * @private |
| * Event listener to add overlay objects when added to the overlay DisplayLayer. |
| */ |
| private function overlay_objectAdd(event:DisplayLayerObjectExistenceEvent):void |
| { |
| super.addChildAt(event.object, event.index + numChildren - _overlay.numDisplayObjects + 1); |
| } |
| |
| /** |
| * @private |
| * Event listener to remove overlay objects when removed from the overlay |
| * DisplayLayer. |
| */ |
| private function overlay_objectRemove(event:DisplayLayerObjectExistenceEvent):void |
| { |
| // Remove the object from the display list |
| super.removeChild(event.object); |
| |
| // Is this the last display object? |
| if (_overlay.numDisplayObjects == 1) |
| invalidateProperties(); |
| } |
| |
| /** |
| * Destroys the overlay object. This method gets called on commitProperties |
| * when the overlay doesn't contain any objects. |
| */ |
| private function destroyOverlay():void |
| { |
| _overlay.removeEventListener(DisplayLayerObjectExistenceEvent.OBJECT_ADD, overlay_objectAdd); |
| _overlay.removeEventListener(DisplayLayerObjectExistenceEvent.OBJECT_REMOVE, overlay_objectRemove); |
| _overlay = null; |
| } |
| |
| //---------------------------------- |
| // resizeMode |
| //---------------------------------- |
| |
| private var _resizeMode:String = ResizeMode.NO_SCALE; |
| |
| [Inspectable(category="General", enumeration="noScale,scale", defaultValue="noScale")] |
| |
| /** |
| * The ResizeMode for this container. If the resize mode |
| * is set to <code>ResizeMode.NO_SCALE</code>, resizing is done by laying |
| * out the children with the new width and height. If the |
| * resize mode is set to <code>ResizeMode.SCALE</code>, all of the children |
| * keep their unscaled width and height and the children |
| * are scaled to change size. |
| * |
| * <p>The default value is <code>ResizeMode.NO_SCALE</code>, corresponding to "noScale".</p> |
| * |
| * @see spark.components.ResizeMode |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get resizeMode():String |
| { |
| return _resizeMode; |
| } |
| |
| public function set resizeMode(value:String):void |
| { |
| if (_resizeMode == value) |
| return; |
| |
| // If old value was scale, reset it |
| if (_resizeMode == ResizeMode.SCALE) |
| setStretchXY(1, 1); |
| |
| _resizeMode = value; |
| |
| // We need the measured values and _resizeMode affects |
| // our measure (skipMeasure implementation checks resizeMode) so |
| // we need to invalidate the size. |
| invalidateSize(); |
| |
| // Invalidate the display list so that our validateMatrix() gets called. |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // mouseOpaque |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the mouseOpaque property |
| */ |
| private var _mouseEnabledWhereTransparent:Boolean = true; |
| private var mouseEventReferenceCount:int; |
| |
| [Inspectable(category="General", enumeration="true,false", defaultValue="true")] |
| |
| /** |
| * When <code>true</code>, this property |
| * ensures that the entire bounds of the Group respond to |
| * mouse events such as click and roll over. |
| * |
| * This property only goes in to effect if mouse, touch, or |
| * flash player gesture events are added to this instance. In addition, |
| * it assumes that the calls to addEventListener()/removeEventListener() |
| * are not superfluous. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get mouseEnabledWhereTransparent():Boolean |
| { |
| return _mouseEnabledWhereTransparent; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set mouseEnabledWhereTransparent(value:Boolean):void |
| { |
| if (value == _mouseEnabledWhereTransparent) |
| return; |
| |
| _mouseEnabledWhereTransparent = value; |
| |
| if (_hasMouseListeners) |
| invalidateDisplayList(); |
| } |
| |
| /** |
| * @private |
| * Renders a background for the container, if necessary. It is used to fill in |
| * a transparent background fill as necessary to support the _mouseEnabledWhereTransparent flag. It |
| * is also used in ItemRenderers when handleBackgroundColor is set to true. |
| * We assume for now that we are the first layer to be rendered into the graphics |
| * context. |
| */ |
| mx_internal function drawBackground():void |
| { |
| if (!_mouseEnabledWhereTransparent || !_hasMouseListeners) |
| return; |
| |
| var w:Number = (_resizeMode == ResizeMode.SCALE) ? measuredWidth : unscaledWidth; |
| var h:Number = (_resizeMode == ResizeMode.SCALE) ? measuredHeight : unscaledHeight; |
| |
| if (isNaN(w) || isNaN(h)) |
| return; |
| |
| graphics.clear(); |
| graphics.beginFill(0xFFFFFF, 0); |
| |
| if (layout && layout.useVirtualLayout) |
| graphics.drawRect(horizontalScrollPosition, verticalScrollPosition, w, h); |
| else |
| { |
| const tileSize:int = 4096; |
| const maxX:int = Math.round(Math.max(w, contentWidth)); |
| const maxY:int = Math.round(Math.max(h, contentHeight)); |
| for (var x:int = 0; x < maxX; x += tileSize) |
| for (var y:int = 0; y < maxY; y += tileSize) |
| { |
| var tileWidth:int = Math.min(maxX - x, tileSize); |
| var tileHeight:int = Math.min(maxY - y, tileSize); |
| graphics.drawRect(x, y, tileWidth, tileHeight); |
| } |
| } |
| |
| graphics.endFill(); |
| } |
| |
| //---------------------------------- |
| // hasMouseListeners |
| //---------------------------------- |
| |
| private var _hasMouseListeners:Boolean = false; |
| |
| /** |
| * @private |
| * |
| * This is a protected helper property used when selectively rendering |
| * the fill layer for mouseOpaque (we only render when we have active |
| * mouse event listeners). |
| * |
| */ |
| mx_internal function set hasMouseListeners(value:Boolean):void |
| { |
| if (_mouseEnabledWhereTransparent) |
| $invalidateDisplayList(); |
| _hasMouseListeners = value; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function get hasMouseListeners():Boolean |
| { |
| return _hasMouseListeners; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function canSkipMeasurement():Boolean |
| { |
| // We never want to skip measure, if we resize by scaling |
| return _resizeMode == ResizeMode.SCALE ? false : super.canSkipMeasurement(); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function invalidateSize():void |
| { |
| super.invalidateSize(); |
| layoutInvalidateSizeFlag = true; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function invalidateDisplayList():void |
| { |
| super.invalidateDisplayList(); |
| layoutInvalidateDisplayListFlag = true; |
| } |
| |
| /** |
| * @private |
| * Called when the child transform changes (currently x and y on UIComponent), |
| * so that the Group has a chance to invalidate the layout. |
| */ |
| override mx_internal function childXYChanged():void |
| { |
| if (autoLayout) |
| { |
| invalidateSize(); |
| invalidateDisplayList(); |
| } |
| } |
| |
| /** |
| * @private |
| * Invalidates the size, but doesn't run layout measure pass. This is useful |
| * for subclasses like Group that perform additional work there - like running |
| * the graphic element measure pass. |
| */ |
| mx_internal function $invalidateSize():void |
| { |
| super.invalidateSize(); |
| } |
| |
| /** |
| * @private |
| * Invalidates the display list, but doesn't run layout updateDisplayList pass. |
| * This is useful for subclasses like Group that perform additional work on |
| * updateDisplayList - like redrawing the graphic elements. |
| */ |
| mx_internal function $invalidateDisplayList():void |
| { |
| super.invalidateDisplayList(); |
| } |
| |
| /** |
| * <p>If the layout object has not been set yet, |
| * createChildren() assigns this container a |
| * default layout object, BasicLayout.</p> |
| * |
| * @copy mx.core.UIComponent:createChildren() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| if (!layout) |
| layout = new BasicLayout(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitProperties():void |
| { |
| super.commitProperties(); |
| |
| // Cleanup the _overlay object when there are no more overlay objects |
| if (_overlay && _overlay.numDisplayObjects == 0) |
| destroyOverlay(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function measure():void |
| { |
| if (_layout && layoutInvalidateSizeFlag) |
| { |
| var oldMeasuredWidth:Number = measuredWidth; |
| var oldMeasuredHeight:Number = measuredHeight; |
| |
| super.measure(); |
| |
| layoutInvalidateSizeFlag = false; |
| _layout.measure(); |
| |
| // Special case: If the group clips content, or resizeMode is "scale" |
| // then measured minimum size is zero |
| if (clipAndEnableScrolling || resizeMode == ResizeMode.SCALE) |
| { |
| measuredMinWidth = 0; |
| measuredMinHeight = 0; |
| } |
| |
| // Make sure that we invalidate the display list if the measured |
| // size changes, as we always size our content at the measured size when in scale mode. |
| if (_resizeMode == ResizeMode.SCALE && (measuredWidth != oldMeasuredWidth || measuredHeight != oldMeasuredHeight)) |
| invalidateDisplayList(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function validateMatrix():void |
| { |
| // Update the stretchXY before the matrix gets validates |
| if (_resizeMode == ResizeMode.SCALE) |
| { |
| var stretchX:Number = 1; |
| var stretchY:Number = 1; |
| |
| if (measuredWidth != 0) |
| stretchX = width / measuredWidth; |
| if (measuredHeight != 0) |
| stretchY = height / measuredHeight; |
| |
| setStretchXY(stretchX, stretchY); |
| } |
| super.validateMatrix(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| var shaderFilter:ShaderFilter; |
| |
| if (_resizeMode == ResizeMode.SCALE) |
| { |
| unscaledWidth = measuredWidth; |
| unscaledHeight = measuredHeight; |
| } |
| |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| if (maskChanged) |
| { |
| maskChanged = false; |
| if (_mask) |
| { |
| maskTypeChanged = true; |
| |
| if (!_mask.parent) |
| { |
| // TODO (jszeto): Does this need to be attached to a sibling? |
| overlay.addDisplayObject(_mask, OverlayDepth.MASK); |
| |
| MaskUtil.applyMask(_mask, null); |
| } |
| } |
| } |
| |
| if (luminositySettingsChanged) |
| { |
| luminositySettingsChanged = false; |
| |
| if (_mask && _maskType == MaskType.LUMINOSITY && _mask.filters.length > 0) |
| { |
| // Grab the shader filter |
| var shaderFilterIndex:int; |
| var len:int = _mask.filters.length; |
| for (shaderFilterIndex = 0; shaderFilterIndex < len; shaderFilterIndex++) |
| { |
| if (_mask.filters[shaderFilterIndex] is ShaderFilter && |
| ShaderFilter(_mask.filters[shaderFilterIndex]).shader is LuminosityMaskShader) |
| { |
| shaderFilter = _mask.filters[shaderFilterIndex]; |
| break; |
| } |
| } |
| |
| if (shaderFilter && (shaderFilter.shader is LuminosityMaskShader)) |
| { |
| // Reset the mode property |
| LuminosityMaskShader(shaderFilter.shader).mode = calculateLuminositySettings(); |
| |
| // Re-apply the filter to the mask |
| _mask.filters[shaderFilterIndex] = shaderFilter; |
| _mask.filters = _mask.filters; |
| } |
| } |
| } |
| |
| if (maskTypeChanged) |
| { |
| maskTypeChanged = false; |
| |
| if (_mask) |
| { |
| if (_maskType == MaskType.CLIP) |
| { |
| // Turn off caching on mask |
| _mask.cacheAsBitmap = false; |
| // Save the original filters and clear the filters property |
| originalMaskFilters = _mask.filters; |
| _mask.filters = []; |
| } |
| else if (_maskType == MaskType.ALPHA) |
| { |
| _mask.cacheAsBitmap = true; |
| cacheAsBitmap = true; |
| } |
| else if (_maskType == MaskType.LUMINOSITY) |
| { |
| _mask.cacheAsBitmap = true; |
| cacheAsBitmap = true; |
| |
| // Create the shader class which wraps the pixel bender filter |
| var luminosityMaskShader:LuminosityMaskShader = new LuminosityMaskShader(); |
| |
| // Sets up the shader's mode property based on |
| // whether the luminosityClip and |
| // luminosityInvert properties are on or off. |
| luminosityMaskShader.mode = calculateLuminositySettings(); |
| |
| // Create the shader filter |
| shaderFilter = new ShaderFilter(luminosityMaskShader); |
| |
| // Apply the shader filter to the mask |
| _mask.filters = [shaderFilter]; |
| } |
| } |
| } |
| |
| if (layoutInvalidateDisplayListFlag) |
| { |
| layoutInvalidateDisplayListFlag = false; |
| if (autoLayout && _layout) |
| _layout.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| if (_layout) |
| _layout.updateScrollRect(unscaledWidth, unscaledHeight); |
| } |
| } |
| |
| /** |
| * @private |
| * Calculates the luminosity mask shader's mode property which |
| * determines how the shader is drawn. |
| */ |
| private function calculateLuminositySettings():int |
| { |
| var mode:int = 0; |
| if (luminosityInvert) |
| mode += 1; |
| if (luminosityClip) |
| mode += 2; |
| return mode; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| super.styleChanged(styleProp); |
| var allStyles:Boolean = (styleProp == null || styleProp == "styleName"); |
| |
| if (!enabled && (allStyles || styleProp == "disabledAlpha")) |
| { |
| var disabledAlpha:Number = getStyle("disabledAlpha"); |
| |
| if (!isNaN(disabledAlpha)) |
| super.alpha = disabledAlpha; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function globalToLocal(point:Point):Point |
| { |
| if (resizeMode == ResizeMode.SCALE && _layoutFeatures != null) |
| { |
| // If resize mode is scale, then globalToLocal shouldn't account for |
| // stretchX/Y |
| var sX:Number = _layoutFeatures.stretchX; |
| var sY:Number = _layoutFeatures.stretchY; |
| _layoutFeatures.stretchX = 1; |
| _layoutFeatures.stretchY = 1; |
| applyComputedMatrix(); |
| |
| var p:Point = super.globalToLocal(point); |
| |
| // Restore stretch |
| _layoutFeatures.stretchX = sX; |
| _layoutFeatures.stretchY = sY; |
| applyComputedMatrix(); |
| |
| return p; |
| } |
| else |
| { |
| return super.globalToLocal(point); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function localToGlobal(point:Point):Point |
| { |
| if (resizeMode == ResizeMode.SCALE && _layoutFeatures != null) |
| { |
| // If resize mode is scale, then localToGlobal shouldn't account for |
| // stretchX/Y |
| var sX:Number = _layoutFeatures.stretchX; |
| var sY:Number = _layoutFeatures.stretchY; |
| _layoutFeatures.stretchX = 1; |
| _layoutFeatures.stretchY = 1; |
| applyComputedMatrix(); |
| |
| var p:Point = super.localToGlobal(point); |
| |
| // Restore stretch |
| _layoutFeatures.stretchX = sX; |
| _layoutFeatures.stretchY = sY; |
| applyComputedMatrix(); |
| |
| return p; |
| } |
| else |
| { |
| return super.localToGlobal(point); |
| } |
| } |
| |
| //---------------------------------- |
| // horizontal,verticalScrollPositionDelta |
| //---------------------------------- |
| |
| /** |
| * @copy spark.layouts.supportClasses.LayoutBase#getHorizontalScrollPositionDelta() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getHorizontalScrollPositionDelta(navigationUnit:uint):Number |
| { |
| return (layout) ? layout.getHorizontalScrollPositionDelta(navigationUnit) : 0; |
| } |
| |
| /** |
| * @copy spark.layouts.supportClasses.LayoutBase#getVerticalScrollPositionDelta() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getVerticalScrollPositionDelta(navigationUnit:uint):Number |
| { |
| return (layout) ? layout.getVerticalScrollPositionDelta(navigationUnit) : 0; |
| } |
| |
| /** |
| * @private |
| * @copy spark.layouts.supportClasses.LayoutBase#isElementVisible() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| mx_internal function isElementVisible(elt:ILayoutElement):Boolean |
| { |
| return layout && layout.isElementVisible(elt); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // IViewport properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // contentWidth |
| //---------------------------------- |
| |
| private var _contentWidth:Number = 0; |
| |
| [Bindable("propertyChange")] |
| [Inspectable(category="General")] |
| |
| /** |
| * @copy spark.core.IViewport#contentWidth |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get contentWidth():Number |
| { |
| return _contentWidth; |
| } |
| |
| /** |
| * @private |
| */ |
| private function setContentWidth(value:Number):void |
| { |
| if (value == _contentWidth) |
| return; |
| var oldValue:Number = _contentWidth; |
| _contentWidth = value; |
| dispatchPropertyChangeEvent("contentWidth", oldValue, value); |
| } |
| |
| //---------------------------------- |
| // contentHeight |
| //---------------------------------- |
| |
| private var _contentHeight:Number = 0; |
| |
| [Bindable("propertyChange")] |
| [Inspectable(category="General")] |
| |
| /** |
| * @copy spark.core.IViewport#contentHeight |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get contentHeight():Number |
| { |
| return _contentHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| private function setContentHeight(value:Number):void |
| { |
| if (value == _contentHeight) |
| return; |
| var oldValue:Number = _contentHeight; |
| _contentHeight = value; |
| dispatchPropertyChangeEvent("contentHeight", oldValue, value); |
| } |
| |
| /** |
| * Sets the <code>contentWidth</code> and <code>contentHeight</code> |
| * properties. |
| * |
| * This method is intended for layout class developers who should |
| * call it from <code>updateDisplayList()</code> methods. |
| * |
| * @param width The new value of <code>contentWidth</code>. |
| * |
| * @param height The new value of <code>contentHeight</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function setContentSize(width:Number, height:Number):void |
| { |
| if ((width == _contentWidth) && (height == _contentHeight)) |
| return; |
| setContentWidth(width); |
| setContentHeight(height); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: EventDispatcher |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * We render a transparent background fill by default when we have mouse |
| * listeners. |
| */ |
| 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); |
| |
| // This code below is not really accurate for two reasons: |
| // 1) MouseEvents bubble so someone up the chain |
| // may be listening for this event, and we woudln't |
| // detect it here. |
| // 2) addEventListener()/removeEventListener() may be called |
| // multiple times with the same handler and may have no |
| // real effect on the component, but we're still incrementing |
| // and decrementing the mouseEventReferenceCount here |
| // Neither of these issues seem worth fixing as there aren't |
| // really great fixes for them, so it's just something we will |
| // document and live with for now. |
| |
| // mouse events, then touch events, then gesture events |
| switch (type) |
| { |
| |
| case MouseEvent.CLICK: |
| case MouseEvent.DOUBLE_CLICK: |
| case MouseEvent.MOUSE_DOWN: |
| case MouseEvent.MOUSE_MOVE: |
| case MouseEvent.MOUSE_OVER: |
| case MouseEvent.MOUSE_OUT: |
| case MouseEvent.ROLL_OUT: |
| case MouseEvent.ROLL_OVER: |
| case MouseEvent.MOUSE_UP: |
| case MouseEvent.MOUSE_WHEEL: |
| case TouchEvent.TOUCH_BEGIN: |
| case TouchEvent.TOUCH_END: |
| case TouchEvent.TOUCH_MOVE: |
| case TouchEvent.TOUCH_OUT: |
| case TouchEvent.TOUCH_OVER: |
| case TouchEvent.TOUCH_ROLL_OUT: |
| case TouchEvent.TOUCH_ROLL_OVER: |
| case TouchEvent.TOUCH_TAP: |
| case GestureEvent.GESTURE_TWO_FINGER_TAP: |
| case PressAndTapGestureEvent.GESTURE_PRESS_AND_TAP: |
| case TransformGestureEvent.GESTURE_PAN: |
| case TransformGestureEvent.GESTURE_ROTATE: |
| case TransformGestureEvent.GESTURE_SWIPE: |
| case TransformGestureEvent.GESTURE_ZOOM: |
| if (mouseEventReferenceCount++ == 0) |
| hasMouseListeners = true; |
| } |
| } |
| |
| /** |
| * @private |
| * We no longer render our default transparent background fill when we have |
| * no mouse listeners. |
| */ |
| override public function removeEventListener( type:String, listener:Function, |
| useCapture:Boolean = false):void |
| { |
| super.removeEventListener(type, listener, useCapture); |
| |
| // see comment above in addEventListener() |
| // mouse events, then touch events, then gesture events |
| switch (type) |
| { |
| |
| case MouseEvent.CLICK: |
| case MouseEvent.DOUBLE_CLICK: |
| case MouseEvent.MOUSE_DOWN: |
| case MouseEvent.MOUSE_MOVE: |
| case MouseEvent.MOUSE_OVER: |
| case MouseEvent.MOUSE_OUT: |
| case MouseEvent.ROLL_OUT: |
| case MouseEvent.ROLL_OVER: |
| case MouseEvent.MOUSE_UP: |
| case MouseEvent.MOUSE_WHEEL: |
| case TouchEvent.TOUCH_BEGIN: |
| case TouchEvent.TOUCH_END: |
| case TouchEvent.TOUCH_MOVE: |
| case TouchEvent.TOUCH_OUT: |
| case TouchEvent.TOUCH_OVER: |
| case TouchEvent.TOUCH_ROLL_OUT: |
| case TouchEvent.TOUCH_ROLL_OVER: |
| case TouchEvent.TOUCH_TAP: |
| case GestureEvent.GESTURE_TWO_FINGER_TAP: |
| case PressAndTapGestureEvent.GESTURE_PRESS_AND_TAP: |
| case TransformGestureEvent.GESTURE_PAN: |
| case TransformGestureEvent.GESTURE_ROTATE: |
| case TransformGestureEvent.GESTURE_SWIPE: |
| case TransformGestureEvent.GESTURE_ZOOM: |
| if (--mouseEventReferenceCount == 0) |
| hasMouseListeners = false; |
| } |
| } |
| |
| /** |
| * @private |
| * Automation requires a version of addEventListener that does not |
| * affect behavior of the underlying 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 |
| * Automation requires a version of removeEventListener that does not |
| * affect behavior of the underlying component. |
| */ |
| mx_internal function $removeEventListener( |
| type:String, listener:Function, |
| useCapture:Boolean = false):void |
| { |
| super.removeEventListener(type, listener, useCapture); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties: Overridden Focus management |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // focusPane |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the focusPane property. |
| */ |
| private var _focusPane:Sprite; |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * @private |
| */ |
| override public function get focusPane():Sprite |
| { |
| return _focusPane; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set focusPane(value:Sprite):void |
| { |
| if (value) |
| { |
| overlay.addDisplayObject(value, OverlayDepth.FOCUS_PANE); |
| |
| value.x = 0; |
| value.y = 0; |
| value.scrollRect = null; |
| |
| _focusPane = value; |
| } |
| else |
| { |
| overlay.removeDisplayObject(_focusPane); |
| |
| // TODO (jszeto): remove mask? SDK-15310 |
| _focusPane = null; |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Layout item iteration |
| // |
| // Iterators used by Layout objects. For visual items, the layout item |
| // is the item itself. For data items, the layout item is the item renderer |
| // instance that is associated with the item. |
| // |
| // These methods and getters are really abstract methods that are |
| // implemented in Group and DataGroup. We need them here in BaseGroup |
| // so that layouts can use these methods. |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#numElements |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get numElements():int |
| { |
| return -1; |
| } |
| |
| /** |
| * @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 null; |
| } |
| |
| /** |
| * Layouts that honor the <code>useVirtualLayout</code> flag will use this |
| * method at updateDisplayList() time to get layout elements that are "in view", |
| * i.e. that overlap the Group's scrollRect. |
| * |
| * <p>If the element to be returned wasn't already a visible child, i.e. if |
| * it was created or recycled, and either eltWidth or eltHeight is specified, |
| * then the element's initial size is set with setLayoutBoundsSize() before |
| * it's validated. This is important for components, like text, that reflow |
| * when the layout is justified to the Group's width or height.</p> |
| * |
| * <p>The returned layout element will have been validated.</p> |
| * |
| * <p>This method will lazily create or "recycle" and validate layout |
| * elements as needed.</p> |
| * |
| * <p>This method is not intended to be called directly, layouts that |
| * support virutalization will call it.</p> |
| * |
| * @param index The index of the element to retrieve. |
| * @param eltWidth If specified, the newly created or recycled element's initial width. |
| * @param eltHeight If specified, the newly created or recycled element's initial height. |
| * @return The validated element at the specified index. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getVirtualElementAt(index:int, eltWidth:Number=NaN, eltHeight:Number=NaN):IVisualElement |
| { |
| return getElementAt(index); |
| } |
| |
| /** |
| * @copy mx.core.IVisualElementContainer#getElementIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function getElementIndex(element:IVisualElement):int |
| { |
| return -1; |
| } |
| |
| /** |
| * Determines whether the specified IVisualElement is a |
| * child of the container instance or the instance |
| * itself. The search is deep, i.e. if the element is |
| * a child, grandchild, great-grandchild, etc., of this |
| * container, this returns true. |
| * |
| * @param element the child object to test |
| * @return true if the element is a descendant of the container |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| * |
| */ |
| public function containsElement(element:IVisualElement):Boolean |
| { |
| while (element) |
| { |
| if (element == this) |
| return true; |
| |
| if (element.parent is IVisualElement) |
| element = IVisualElement(element.parent); |
| else |
| return false; |
| } |
| |
| return false; |
| } |
| |
| //---------------------------------- |
| // mask |
| //---------------------------------- |
| |
| private var _mask:DisplayObject; |
| mx_internal var maskChanged:Boolean; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * Sets the mask. The mask will be added to the display list. The mask must |
| * not already on a display list nor in the elements array. |
| * |
| * @see flash.display.DisplayObject#mask |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| override public function get mask():DisplayObject |
| { |
| return _mask; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set mask(value:DisplayObject):void |
| { |
| if (_mask !== value) |
| { |
| if (_mask && _mask.parent === this) |
| { |
| overlay.removeDisplayObject(_mask); |
| } |
| |
| _mask = value; |
| maskChanged = true; |
| invalidateDisplayList(); |
| } |
| super.mask = value; |
| } |
| |
| //---------------------------------- |
| // maskType |
| //---------------------------------- |
| |
| private var _maskType:String = MaskType.CLIP; |
| private var maskTypeChanged:Boolean; |
| private var originalMaskFilters:Array; |
| |
| [Bindable("propertyChange")] |
| [Inspectable(category="General", enumeration="clip,alpha,luminosity", defaultValue="clip")] |
| |
| /** |
| * <p>The mask type. Possible values are <code>MaskType.CLIP</code>, <code>MaskType.ALPHA</code> |
| * or <code>MaskType.LUMINOSITY</code>.</p> |
| * |
| * <p><b>Clip Masking</b></p> |
| * |
| * <p>When masking in clip mode, a clipping masks is reduced to 1-bit. This means that a mask will |
| * not affect the opacity of a pixel in the source content; it either leaves the value unmodified, |
| * if the corresponding pixel in the mask is has a non-zero alpha value, or makes it fully |
| * transparent, if the mask pixel value has an alpha value of zero.</p> |
| * |
| * <p><b>Alpha Masking</b></p> |
| * |
| * <p>In alpha mode, the opacity of each pixel in the source content is multiplied by the opacity |
| * of the corresponding region of the mask. i.e., a pixel in the source content with an opacity of |
| * 1 that is masked by a region of opacity of .5 will have a resulting opacity of .5. A source pixel |
| * with an opacity of .8 masked by a region with opacity of .5 will have a resulting opacity of .4.</p> |
| * |
| * <p><b>Luminosity Masking</b></p> |
| * |
| * <p>A luminosity mask, sometimes called a 'soft mask', works very similarly to an alpha mask |
| * except that both the opacity and RGB color value of a pixel in the source content is multiplied |
| * by the opacity and RGB color value of the corresponding region in the mask.</p> |
| * |
| * <p>Luminosity masking is not native to Flash but is common in Adobe Creative Suite tools like Adobe |
| * Illustrator and Adobe Photoshop. In order to accomplish the visual effect of a luminosity mask in |
| * Flash-rendered content, a graphic element specifying a luminosity mask actually instantiates a shader |
| * filter that mimics the visual look of a luminosity mask as rendered in Adobe Creative Suite tools.</p> |
| * |
| * <p>Objects being masked by luminosity masks can set properties to control the RGB color value and |
| * clipping of the mask. See the luminosityInvert and luminosityClip attributes.</p> |
| * |
| * @default MaskType.CLIP |
| * |
| * @see spark.core.MaskType |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get maskType():String |
| { |
| return _maskType; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set maskType(value:String):void |
| { |
| if (_maskType != value) |
| { |
| _maskType = value; |
| maskTypeChanged = true; |
| invalidateDisplayList(); |
| } |
| } |
| |
| //---------------------------------- |
| // luminosityInvert |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the luminosityInvert property. |
| */ |
| private var _luminosityInvert:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var luminositySettingsChanged:Boolean; |
| |
| [Inspectable(category="General", enumeration="true,false", defaultValue="false")] |
| |
| /** |
| * A property that controls the calculation of the RGB |
| * color value of a graphic element being masked by |
| * a luminosity mask. If true, the RGB color value of a |
| * pixel in the source content is inverted and multipled |
| * by the corresponding region in the mask. If false, |
| * the source content's pixel's RGB color value is used |
| * directly. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get luminosityInvert():Boolean |
| { |
| return _luminosityInvert; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set luminosityInvert(value:Boolean):void |
| { |
| if (_luminosityInvert == value) |
| return; |
| |
| _luminosityInvert = value; |
| luminositySettingsChanged = true; |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // luminosityClip |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the luminosityClip property. |
| */ |
| private var _luminosityClip:Boolean = false; |
| |
| [Inspectable(category="General", enumeration="true,false", defaultValue="false")] |
| |
| /** |
| * A property that controls whether the luminosity |
| * mask clips the masked content. This property can |
| * only have an effect if the graphic element has a |
| * mask applied to it that is of type |
| * MaskType.LUMINOSITY. |
| * |
| * @default false |
| * @see #maskType |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get luminosityClip():Boolean |
| { |
| return _luminosityClip; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set luminosityClip(value:Boolean):void |
| { |
| if (_luminosityClip == value) |
| return; |
| |
| _luminosityClip = value; |
| luminositySettingsChanged = true; |
| invalidateDisplayList(); |
| } |
| |
| /** |
| * @private |
| * |
| * A simple insertion sort. This works well for small lists (under 12 or so), uses |
| * no aditional memory, and most importantly, is stable, meaning items with comparable |
| * values will stay in the same order relative to each other. For layering, we guarantee |
| * first the layer property, and then the item order, so a stable sort is important (and the |
| * built in flash sort is not stable). |
| */ |
| mx_internal static function sortOnLayer(a:Vector.<IVisualElement>):void |
| { |
| var len:Number = a.length; |
| var tmp:IVisualElement; |
| if (len<= 1) |
| return; |
| for (var i:int = 1;i<len;i++) |
| { |
| for (var j:int = i;j > 0;j--) |
| { |
| if ( a[j].depth < a[j-1].depth ) |
| { |
| tmp = a[j]; |
| a[j] = a[j-1]; |
| a[j-1] = tmp; |
| } |
| else |
| break; |
| } |
| } |
| } |
| |
| } |
| |
| } |