| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.core |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.Graphics; |
| import flash.display.Shape; |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| |
| import mx.controls.HScrollBar; |
| import mx.controls.VScrollBar; |
| import mx.controls.scrollClasses.ScrollBar; |
| import mx.core.IToolTip; |
| import mx.events.ScrollEvent; |
| import mx.events.ScrollEventDetail; |
| import mx.events.ScrollEventDirection; |
| import mx.managers.ToolTipManager; |
| import mx.styles.ISimpleStyleClient; |
| |
| use namespace mx_internal; |
| |
| /** |
| * Dispatched when the content is scrolled. |
| * |
| * @eventType mx.events.ScrollEvent.SCROLL |
| * @helpid 3269 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Event(name="scroll", type="mx.events.ScrollEvent")] |
| |
| include "../styles/metadata/BackgroundStyles.as" |
| include "../styles/metadata/BorderStyles.as" |
| include "../styles/metadata/FocusStyles.as" |
| include "../styles/metadata/LeadingStyle.as" |
| include "../styles/metadata/TextStyles.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")] |
| |
| /** |
| * The main color for a component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="chromeColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * 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. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="cornerRadius", type="Number", format="Length", inherit="no", theme="halo")] |
| |
| /** |
| * 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")] |
| |
| /** |
| * Style name for horizontal scrollbar. This allows more control over |
| * the appearance of the scrollbar. |
| * |
| * @default undefined |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="horizontalScrollBarStyleName", type="String", 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")] |
| |
| /** |
| * Style name for vertical scrollbar. This allows more control over |
| * the appearance of the scrollbar. |
| * |
| * @default undefined |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="verticalScrollBarStyleName", type="String", inherit="no")] |
| |
| /** |
| * The ScrollControlBase class is the base class for controls |
| * with scroll bars. |
| * The user interacts with the scroll bar or the developer accesses |
| * methods and properties that alter the viewable area. |
| * The ScrollControlBase takes a single child object and positions and |
| * masks or sizes that object to display the viewable content. |
| * All items to be scrolled must be children of that content object |
| * |
| * @mxml |
| * |
| * <p>The <code><ScrollControlBase></code> tag inherits all the tag attributes |
| * of its superclass, and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <mx:<i>tagname</i> |
| * <b>Properties</b> |
| * border="<i>object of border skin style</i>" |
| * horizontalScrollPolicy="off|on|auto" |
| * horizontalScrollPosition="0" |
| * liveScrolling="true|false" |
| * maxHorizontalScrollPosition="NaN" |
| * maxVerticalScrollPosition="NaN" |
| * scrollTipFunction="undefined" |
| * showScrollTips="false|true" |
| * verticalScrollPolicy="auto|off|on" |
| * verticalScrollPosition="0" |
| * <b>Styles</b> |
| * backgroundAlpha="1.0" |
| * backgroundColor="undefined" |
| * backgroundImage="undefined" |
| * backgroundSize="auto" |
| * borderColor="0xAAB3B3" |
| * borderSides="left top right bottom" |
| * borderSkin="ClassReference('mx.skins.halo.HaloBorder')" |
| * borderStyle="inset" |
| * borderThickness="1" |
| * color="0x0B333C" |
| * cornerRadius="0" |
| * disabledColor="0xAAB3B3" |
| * dropShadowColor="0x000000" |
| * dropShadowEnabled="false" |
| * fontFamily="Verdana" |
| * fontSize="10" |
| * fontStyle="normal|italic" |
| * fontWeight="normal|bold" |
| * horizontalScrollBarStyleName="" |
| * leading="2" |
| * shadowDirection="center" |
| * shadowDistance="2" |
| * textAlign="<i>value; see detail.</i>" |
| * textDecoration="none|underline" |
| * textIndent="0" |
| * verticalScrollBarStyleName="" |
| * |
| * <b>Events</b> |
| * scroll="<i>No default</i>" |
| * /> |
| * </pre> |
| * |
| * @helpid 3270 |
| * @tiptext base class for views/containers that support scrolling |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class ScrollControlBase extends UIComponent |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function ScrollControlBase() |
| { |
| super(); |
| |
| _viewMetrics = EdgeMetrics.EMPTY; |
| |
| // Listen for "mouseWheel" events on myself or any of my children |
| addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * The border object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var border:IFlexDisplayObject; |
| |
| /** |
| * @private |
| * Offsets including borders and scrollbars. |
| */ |
| private var _viewMetrics:EdgeMetrics; |
| |
| /** |
| * The mask. This property may be undefined if no scroll bars |
| * are currently displayed or in some subclasses which |
| * have a different masking mechanism. |
| * A mask defined the viewable area of a displayable object. |
| * Thus this mask is used to hide the portions of the content |
| * that are not currently viewable. |
| * In general you do not access this property directly. |
| * Manipulation of the <code>horizontalScrollPolicy</code>, |
| * <code>verticalScrollPolicy</code>, <code>horizontalScrollPosition</code>, |
| * and <code>verticalScrollPosition</code> properties |
| * should provide sufficient control over the mask. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var maskShape:Shape; |
| |
| /** |
| * The horizontal scroll bar. |
| * This property is null if no horizontal scroll bar |
| * is currently displayed. |
| * In general you do not access this property directly. |
| * Manipulation of the <code>horizontalScrollPolicy</code> |
| * and <code>horizontalScrollPosition</code> |
| * properties should provide sufficient control over the scroll bar. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var horizontalScrollBar:ScrollBar; |
| |
| /** |
| * The vertical scroll bar. |
| * This property is null if no vertical scroll bar |
| * is currently displayed. |
| * In general you do not access this property directly. |
| * Manipulation of the <code>verticalScrollPolicy</code> |
| * and <code>verticalScrollPosition</code> |
| * properties should provide sufficient control over the scroll bar. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var verticalScrollBar:ScrollBar; |
| |
| /** |
| * @private |
| */ |
| private var numberOfCols:Number = 0; |
| |
| /** |
| * @private |
| */ |
| private var numberOfRows:Number = 0; |
| |
| /** |
| * @private |
| */ |
| mx_internal var _maxVerticalScrollPosition:Number; |
| mx_internal var _maxHorizontalScrollPosition:Number; |
| |
| /** |
| * @private |
| */ |
| private var viewableRows:Number; |
| private var viewableColumns:Number; |
| |
| /** |
| * @private |
| */ |
| private var propsInited:Boolean; |
| |
| /** |
| * A flag that the scrolling area changed due to the appearance or disappearance of |
| * scrollbars. Used by most layout methods to re-adjust the scrolling properties again. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var scrollAreaChanged:Boolean; |
| |
| /** |
| * @private |
| */ |
| private var invLayout:Boolean; |
| |
| /** |
| * @private |
| * Instance of the scrollTip. (There can be only one.) |
| */ |
| private var scrollTip:IToolTip; |
| |
| /** |
| * @private |
| * Base position for the scrollTip. |
| */ |
| private var scrollThumbMidPoint:Number; |
| |
| /** |
| * @private |
| * Keep track of the whether the ToolTipManager was enabled |
| * before dealing with scroll tips. |
| */ |
| private var oldTTMEnabled:Boolean; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // enabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Scrollbars must be enabled/disabled when we are. |
| */ |
| override public function set enabled(value:Boolean):void |
| { |
| super.enabled = value; |
| |
| if (horizontalScrollBar) |
| horizontalScrollBar.enabled = value; |
| |
| if (verticalScrollBar) |
| verticalScrollBar.enabled = value; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // 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. |
| * |
| * @return EdgeMetrics object with the left, right, top, |
| * and bottom properties. |
| * |
| * @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; |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the horizontalScrollPosition property. |
| */ |
| mx_internal var _horizontalScrollPosition:Number = 0; |
| |
| [Bindable("scroll")] |
| [Bindable("viewChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The offset into the content from the left edge. This can |
| * be a pixel offset in some subclasses or some other metric |
| * like the number of columns in a DataGrid or number of items |
| * in a HorizontalList or TileList. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get horizontalScrollPosition():Number |
| { |
| return _horizontalScrollPosition; |
| } |
| |
| /** |
| * @private |
| * This only moves the scrollBars -- assumes the call emanated |
| * from the scrollable content. |
| */ |
| public function set horizontalScrollPosition(value:Number):void |
| { |
| _horizontalScrollPosition = value; |
| |
| if (horizontalScrollBar) |
| horizontalScrollBar.scrollPosition = value; |
| |
| dispatchEvent(new Event("viewChanged")); |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPolicy |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the horizontalScrollPolicy property. |
| */ |
| mx_internal var _horizontalScrollPolicy:String = ScrollPolicy.OFF; |
| |
| [Bindable("horizontalScrollPolicyChanged")] |
| [Inspectable(enumeration="off,on,auto", defaultValue="off")] |
| |
| /** |
| * A property that indicates whether the horizontal scroll |
| * bar is always on, always off, |
| * or automatically changes based on the parameters passed to the |
| * <code>setScrollBarProperties()</code> method. |
| * Allowed 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> for ListBase |
| * subclasses does not affect the <code>horizontalScrollPosition</code> |
| * property; you can still scroll the contents programmatically.</p> |
| * |
| * <p>Note that the policy can affect the measured size of the component |
| * If the policy is <code>ScrollPolicy.AUTO</code> the |
| * scrollbar is not factored in the measured size. This is done to |
| * keep the layout from recalculating when the scrollbar appears. If you |
| * know that you will have enough data for scrollbars you should set |
| * the policy to <code>ScrollPolicy.ON</code>. If you |
| * don't know, you may need to set an explicit width or height on |
| * the component to allow for scrollbars to appear later.</p> |
| * |
| * @default ScrollPolicy.OFF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get horizontalScrollPolicy():String |
| { |
| return _horizontalScrollPolicy; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set horizontalScrollPolicy(value:String):void |
| { |
| var newPolicy:String = value.toLowerCase(); |
| |
| if (_horizontalScrollPolicy != newPolicy) |
| { |
| _horizontalScrollPolicy = newPolicy; |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("horizontalScrollPolicyChanged")); |
| } |
| } |
| |
| //---------------------------------- |
| // liveScrolling |
| //---------------------------------- |
| |
| [Inspectable(defaultValue="true")] |
| |
| /** |
| * A flag that indicates whether scrolling is live as the |
| * scrollbar thumb is moved |
| * or the view is not updated until the thumb is released. |
| * The default value is <code>true</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var liveScrolling:Boolean = true; |
| |
| //---------------------------------- |
| // maxHorizontalScrollPosition |
| //---------------------------------- |
| |
| [Bindable("maxHorizontalScrollPositionChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The maximum value for the <code>horizontalScrollPosition</code> property. |
| * Note that this is not the width of the content because the |
| * <code>maxHorizontalScrollPosition</code> property contains the width |
| * of the content minus the width of the displayable area. |
| * |
| * <p>In most components, the value of the |
| * <code>maxHorizontalScrollPosition</code> property is computed from the |
| * data and size of component, and must not be set by |
| * the application code.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get maxHorizontalScrollPosition():Number |
| { |
| if (!isNaN(_maxHorizontalScrollPosition)) |
| return _maxHorizontalScrollPosition; |
| |
| var m:Number = horizontalScrollBar ? |
| horizontalScrollBar.maxScrollPosition : |
| 0; |
| return m; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set maxHorizontalScrollPosition(value:Number):void |
| { |
| _maxHorizontalScrollPosition = value; |
| |
| dispatchEvent(new Event("maxHorizontalScrollPositionChanged")); |
| } |
| |
| //---------------------------------- |
| // maxVerticalScrollPosition |
| //---------------------------------- |
| |
| [Bindable("maxVerticalScrollPositionChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The maximum value for the <code>verticalScrollPosition</code> property. |
| * Note that this is not the height of the content because the |
| * <code>maxVerticalScrollPosition</code> property contains the height |
| * of the content minus the height of the displayable area. |
| * |
| * <p>The value of the |
| * <code>maxVerticalScrollPosition</code> property is computed from the |
| * data and size of component, and must not be set by |
| * the application code.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get maxVerticalScrollPosition():Number |
| { |
| if (!isNaN(_maxVerticalScrollPosition)) |
| return _maxVerticalScrollPosition; |
| |
| var m:Number = verticalScrollBar ? |
| verticalScrollBar.maxScrollPosition : |
| 0; |
| return m; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set maxVerticalScrollPosition(value:Number):void |
| { |
| _maxVerticalScrollPosition = value; |
| |
| dispatchEvent(new Event("maxVerticalScrollPositionChanged")); |
| } |
| |
| //---------------------------------- |
| // scrollTipFunction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the scrollTipFunction property. |
| */ |
| private var _scrollTipFunction:Function; |
| |
| [Bindable("scrollTipFunctionChanged")] |
| [Inspectable(defaultValue="")] |
| |
| /** |
| * A function that computes the string to be displayed as the ScrollTip. |
| * This function is called if the <code>showScrollTips</code> property |
| * is set to <code>true</code> and the scroll thumb is being dragged. |
| * The function should return a String that used as a ScrollTip. |
| * The function is passed two parameters. |
| * The first is the <code>direction</code> of the scroll bar. |
| * The second is its <code>scrollPosition</code>, as the following example shows: |
| * |
| * <pre> |
| * function scrollTipFunction(direction:String, position:Number):String |
| * { |
| * if (direction == "vertical") return myToolTips[position]; |
| * else return ""; |
| * }</pre> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get scrollTipFunction():Function |
| { |
| return _scrollTipFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set scrollTipFunction(value:Function):void |
| { |
| _scrollTipFunction = value; |
| |
| dispatchEvent(new Event("scrollTipFunctionChanged")); |
| } |
| |
| //---------------------------------- |
| // showScrollTips |
| //---------------------------------- |
| |
| [Inspectable(defaultValue="false")] |
| |
| /** |
| * A flag that indicates whether a tooltip should appear |
| * near the scroll thumb when it is being dragged. |
| * The default value is <code>false</code> to disable the tooltip. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var showScrollTips:Boolean = false; |
| |
| //---------------------------------- |
| // viewMetrics |
| //---------------------------------- |
| |
| /** |
| * An EdgeMetrics object taking into account the scroll bars, |
| * if visible. |
| * |
| * @return EdgeMetrics object with the thickness, in pixels, |
| * of the left, top, right, and bottom edges. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get viewMetrics():EdgeMetrics |
| { |
| _viewMetrics = borderMetrics.clone(); |
| |
| if (!horizontalScrollBar && |
| (horizontalScrollPolicy == ScrollPolicy.ON)) |
| { |
| createHScrollBar(true); |
| |
| horizontalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollHandler); |
| horizontalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollTipHandler); |
| horizontalScrollBar.scrollPosition = _horizontalScrollPosition; |
| |
| invalidateDisplayList(); |
| } |
| |
| if (!verticalScrollBar && verticalScrollPolicy == ScrollPolicy.ON) |
| { |
| createVScrollBar(true); |
| |
| verticalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollHandler); |
| verticalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollTipHandler); |
| verticalScrollBar.scrollPosition = _verticalScrollPosition; |
| |
| invalidateDisplayList(); |
| } |
| |
| if (verticalScrollBar && verticalScrollBar.visible) |
| _viewMetrics.right += verticalScrollBar.minWidth; |
| |
| if (horizontalScrollBar && horizontalScrollBar.visible) |
| _viewMetrics.bottom += horizontalScrollBar.minHeight; |
| |
| return _viewMetrics; |
| } |
| |
| //---------------------------------- |
| // verticalScrollPosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the verticalScrollPosition property. |
| */ |
| mx_internal var _verticalScrollPosition:Number = 0; |
| |
| [Bindable("scroll")] |
| [Bindable("viewChanged")] |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The offset into the content from the top edge. This can |
| * be a pixel offset in some subclasses or some other metric |
| * like number of lines in a List or number of tiles in |
| * a TileList. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get verticalScrollPosition():Number |
| { |
| return _verticalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set verticalScrollPosition(value:Number):void |
| { |
| _verticalScrollPosition = value; |
| |
| if (verticalScrollBar) |
| verticalScrollBar.scrollPosition = value; |
| |
| dispatchEvent(new Event("viewChanged")); |
| } |
| |
| //---------------------------------- |
| // verticalScrollPolicy |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the verticalScrollPolicy property. |
| */ |
| mx_internal var _verticalScrollPolicy:String = ScrollPolicy.AUTO; |
| |
| [Bindable("verticalScrollPolicyChanged")] |
| [Inspectable(enumeration="off,on,auto", defaultValue="auto")] |
| |
| /** |
| * A property that indicates whether the vertical scroll bar is always on, always off, |
| * or automatically changes based on the parameters passed to the |
| * <code>setScrollBarProperties()</code> method. |
| * Allowed 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> for ListBase |
| * subclasses does not affect the <code>verticalScrollPosition</code> |
| * property; you can still scroll the contents programmatically.</p> |
| * |
| * <p>Note that the policy can affect the measured size of the component |
| * If the policy is <code>ScrollPolicy.AUTO</code> the |
| * scrollbar is not factored in the measured size. This is done to |
| * keep the layout from recalculating when the scrollbar appears. If you |
| * know that you will have enough data for scrollbars you should set |
| * the policy to <code>ScrollPolicy.ON</code>. If you |
| * don't know, you may need to set an explicit width or height on |
| * the component to allow for scrollbars to appear later.</p> |
| * |
| * @default ScrollPolicy.AUTO |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get verticalScrollPolicy():String |
| { |
| return _verticalScrollPolicy; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set verticalScrollPolicy(value:String):void |
| { |
| var newPolicy:String = value.toLowerCase(); |
| |
| if (_verticalScrollPolicy != newPolicy) |
| { |
| _verticalScrollPolicy = newPolicy; |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("verticalScrollPolicyChanged")); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Creates objects that are children of this ScrollControlBase, |
| * which in this case are the border and mask. |
| * Flex calls this method when the ScrollControlBase is first created. |
| * If a subclass overrides this method, the subclass should call |
| * the <code>super.createChildren()</code> method so that the logic |
| * in the <code>ScrollControlBase.createChildren()</code> method is executed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| createBorder(); |
| |
| if (!maskShape) |
| { |
| maskShape = new FlexShape(); |
| maskShape.name = "mask"; |
| |
| var g:Graphics = maskShape.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| |
| addChild(maskShape); |
| } |
| |
| maskShape.visible = false; |
| } |
| |
| /** |
| * @private |
| * Sets the position and size of the scroll bars and content |
| * and adjusts the mask. |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| layoutChrome(unscaledWidth, unscaledHeight); |
| |
| var w:Number = unscaledWidth; |
| var h:Number = unscaledHeight; |
| |
| invLayout = false; |
| |
| var vm:EdgeMetrics = _viewMetrics = viewMetrics; |
| |
| if (horizontalScrollBar && horizontalScrollBar.visible) |
| { |
| horizontalScrollBar.setActualSize(w - vm.left - vm.right, |
| horizontalScrollBar.minHeight); |
| horizontalScrollBar.move(vm.left, |
| h - vm.bottom); |
| |
| horizontalScrollBar.enabled = enabled; |
| } |
| |
| if (verticalScrollBar && verticalScrollBar.visible) |
| { |
| verticalScrollBar.setActualSize(verticalScrollBar.minWidth, |
| h - vm.top - vm.bottom); |
| verticalScrollBar.move(w - vm.right, vm.top); |
| |
| verticalScrollBar.enabled = enabled; |
| } |
| |
| var mask:DisplayObject = maskShape; |
| |
| var wd:Number = w - vm.left - vm.right; |
| var ht:Number = h - vm.top - vm.bottom; |
| |
| mask.width = wd < 0 ? 0 : wd; |
| mask.height = ht < 0 ? 0 : ht; |
| |
| mask.x = vm.left; |
| mask.y = vm.top; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| var allStyles:Boolean = (styleProp == null || styleProp == "styleName"); |
| |
| super.styleChanged(styleProp); |
| |
| if (allStyles || styleProp == "horizontalScrollBarStyleName") |
| { |
| if (horizontalScrollBar) |
| { |
| var horizontalScrollBarStyleName:String = |
| getStyle("horizontalScrollBarStyleName"); |
| horizontalScrollBar.styleName = horizontalScrollBarStyleName; |
| } |
| } |
| |
| if (allStyles || styleProp == "verticalScrollBarStyleName") |
| { |
| if (verticalScrollBar) |
| { |
| var verticalScrollBarStyleName:String = |
| getStyle("verticalScrollBarStyleName"); |
| verticalScrollBar.styleName = verticalScrollBarStyleName; |
| } |
| } |
| |
| // Replace the borderSkin |
| if (allStyles || styleProp == "borderSkin") |
| { |
| if (border) |
| { |
| removeChild(DisplayObject(border)); |
| border = null; |
| createBorder(); |
| } |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Responds to size changes by setting the positions and sizes |
| * of this control's borders. |
| * |
| * <p>The <code>ScrollControlBase.layoutChrome()</code> method sets the |
| * position and size of the ScrollControlBase's border. |
| * In every subclass of ScrollControlBase, 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) |
| { |
| border.move(0, 0); |
| border.setActualSize(unscaledWidth, unscaledHeight); |
| } |
| } |
| |
| /** |
| * Creates the border for this component. |
| * Normally the border is determined by the |
| * <code>borderStyle</code> and <code>borderSkin</code> styles. |
| * It must set the border property to the instance |
| * of the border. |
| * |
| * @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(); |
| |
| if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0) |
| { |
| if (border is IUIComponent) |
| IUIComponent(border).enabled = enabled; |
| } |
| if (border is ISimpleStyleClient) |
| ISimpleStyleClient(border).styleName = this; |
| |
| // Add the border behind all the children. |
| addChildAt(DisplayObject(border), 0); |
| |
| invalidateDisplayList(); |
| } |
| } |
| } |
| |
| /** |
| * Returns <code>true</code> if a border is needed for this component based |
| * on the borderStyle and whether or not there is a background |
| * for the component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private function isBorderNeeded():Boolean |
| { |
| //trace("isBorderNeeded",this,"ms",getStyle("mouseShield"),"borderStyle",getStyle("borderStyle")); |
| |
| 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("backgroundColor"); |
| if (v !== null && v !== "") |
| return true; |
| |
| v = getStyle("backgroundImage"); |
| return v != null && v != ""; |
| } |
| |
| /** |
| * Causes the ScrollControlBase to show or hide scrollbars based |
| * on the parameters passed in. If a TextArea can only show 100 pixels |
| * across and 5 lines of text, but the actual text to display is 200 pixels wide |
| * and 30 lines of text, then the <code>setScrollBarProperties()</code> method |
| * is called as |
| * <code>setScrollBarProperties(200, 100, 30, 5)</code>. |
| * |
| * @param totalColumns The number of horizontal units that need to be displayed. |
| * |
| * @param visibleColumns The number of horizontal units that can be displayed at one time. |
| * |
| * @param totalRows The number of vertical units that need to be displayed. |
| * |
| * @param visibleRows The number of vertical units that can be displayed at one time |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function setScrollBarProperties(totalColumns:int, visibleColumns:int, |
| totalRows:int, visibleRows:int):void |
| { |
| var horizontalScrollPolicy:String = this.horizontalScrollPolicy; |
| var verticalScrollPolicy:String = this.verticalScrollPolicy; |
| |
| var shouldBeVisible:Boolean; |
| |
| scrollAreaChanged = false; |
| |
| // scrollbars when the scrollPolicy is ON are calculated in viewMetrics |
| if (horizontalScrollPolicy == ScrollPolicy.ON || |
| (visibleColumns < totalColumns && totalColumns > 0 && |
| (horizontalScrollPolicy == ScrollPolicy.AUTO))) |
| { |
| // We need a horizontal scrollBar. |
| |
| // Nope, need to add it. |
| if (!horizontalScrollBar) |
| { |
| createHScrollBar(false); |
| |
| horizontalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollHandler); |
| horizontalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollTipHandler); |
| |
| horizontalScrollBar.scrollPosition = _horizontalScrollPosition; |
| } |
| |
| shouldBeVisible = roomForScrollBar(horizontalScrollBar, unscaledWidth, unscaledHeight); |
| |
| if (shouldBeVisible != horizontalScrollBar.visible) |
| { |
| horizontalScrollBar.visible = shouldBeVisible; |
| scrollAreaChanged = true; |
| } |
| |
| if (horizontalScrollBar && horizontalScrollBar.visible && (numberOfCols != totalColumns || |
| viewableColumns != visibleColumns || scrollAreaChanged)) |
| { |
| horizontalScrollBar.setScrollProperties( |
| visibleColumns, 0, totalColumns - visibleColumns); |
| |
| if (horizontalScrollBar.scrollPosition != _horizontalScrollPosition) |
| horizontalScrollBar.scrollPosition = _horizontalScrollPosition; |
| |
| viewableColumns = visibleColumns; |
| numberOfCols = totalColumns; |
| } |
| } |
| else if ((horizontalScrollPolicy == ScrollPolicy.AUTO || |
| horizontalScrollPolicy == ScrollPolicy.OFF) && |
| horizontalScrollBar && horizontalScrollBar.visible) |
| { |
| // We need to remove this scrollBar. |
| horizontalScrollPosition = 0; |
| horizontalScrollBar.setScrollProperties( |
| visibleColumns, 0, 0); |
| horizontalScrollBar.visible = false; |
| viewableColumns = NaN; |
| scrollAreaChanged = true; |
| } |
| |
| if (verticalScrollPolicy == ScrollPolicy.ON || |
| (visibleRows < totalRows && totalRows > 0 && |
| (verticalScrollPolicy == ScrollPolicy.AUTO))) |
| { |
| // We need a vertical scrollBar. Does it exist? |
| if (!verticalScrollBar) |
| { |
| // No it doesn't, and we're allowed to add it. |
| createVScrollBar(false); |
| |
| verticalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollHandler); |
| verticalScrollBar.addEventListener(ScrollEvent.SCROLL, scrollTipHandler); |
| |
| verticalScrollBar.scrollPosition = _verticalScrollPosition; |
| } |
| |
| shouldBeVisible = roomForScrollBar(verticalScrollBar, unscaledWidth, unscaledHeight); |
| |
| if (shouldBeVisible != verticalScrollBar.visible) |
| { |
| verticalScrollBar.visible = shouldBeVisible; |
| scrollAreaChanged = true; |
| } |
| |
| if (verticalScrollBar && verticalScrollBar.visible && (numberOfRows != totalRows || |
| (viewableRows != visibleRows) || scrollAreaChanged)) |
| { |
| verticalScrollBar.setScrollProperties( |
| visibleRows, 0, totalRows - visibleRows); |
| |
| if (verticalScrollBar.scrollPosition != _verticalScrollPosition) |
| verticalScrollBar.scrollPosition = _verticalScrollPosition; |
| |
| viewableRows = visibleRows; |
| numberOfRows = totalRows; |
| } |
| } |
| else if ((verticalScrollPolicy == ScrollPolicy.AUTO || |
| verticalScrollPolicy == ScrollPolicy.OFF) && |
| verticalScrollBar && verticalScrollBar.visible) |
| { |
| verticalScrollPosition = 0; |
| verticalScrollBar.setScrollProperties( |
| visibleRows, 0, 0); |
| verticalScrollBar.visible = false; |
| viewableRows = NaN; |
| scrollAreaChanged = true; |
| } |
| |
| // Now, if any scrollBar came into or left existence, |
| // it's possible that the content is occluded or revealed enough |
| // that the other scrollBar needs to appear or go away. |
| if (scrollAreaChanged) |
| { |
| // This is for content that conforms to the (discrete) |
| // scrollable interface. It just falls through on analog content. |
| // (I hope.) |
| updateDisplayList(unscaledWidth, unscaledHeight); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Private methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Create the HScrollBar |
| */ |
| private function createHScrollBar(visible:Boolean):ScrollBar |
| { |
| horizontalScrollBar = new HScrollBar(); |
| horizontalScrollBar.visible = visible; |
| horizontalScrollBar.enabled = enabled; |
| |
| var horizontalScrollBarStyleName:String = |
| getStyle("horizontalScrollBarStyleName"); |
| horizontalScrollBar.styleName = horizontalScrollBarStyleName; |
| |
| // Place the new scrollbar in front of other children |
| // in the ScrollControlBase |
| addChild(horizontalScrollBar); |
| |
| horizontalScrollBar.validateNow(); |
| |
| return horizontalScrollBar; |
| } |
| |
| /** |
| * @private |
| * Create the VScrollBar |
| */ |
| private function createVScrollBar(visible:Boolean):ScrollBar |
| { |
| verticalScrollBar = new VScrollBar(); |
| verticalScrollBar.visible = visible; |
| verticalScrollBar.enabled = enabled; |
| |
| var verticalScrollBarStyleName:String = |
| getStyle("verticalScrollBarStyleName"); |
| verticalScrollBar.styleName = verticalScrollBarStyleName; |
| |
| // Place the new scrollbar in front of other children |
| // in the ScrollControlBase |
| addChild(verticalScrollBar); |
| |
| //need verticalScrollBar.validateNow()? |
| UIComponentGlobals.layoutManager.validateClient(verticalScrollBar, true); |
| |
| return verticalScrollBar; |
| } |
| |
| /** |
| * Determines if there is enough space in this component to display |
| * a given scrollbar. |
| * |
| * @param bar The scrollbar |
| * |
| * @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. |
| * |
| * @return Returns true if there is enough space for a scrollbar. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| |
| protected function roomForScrollBar(bar:ScrollBar, |
| unscaledWidth:Number, unscaledHeight:Number):Boolean |
| { |
| var bm:EdgeMetrics = borderMetrics; |
| return (unscaledWidth >= bar.minWidth + bm.left + bm.right) && |
| (unscaledHeight >= bar.minHeight + bm.top + bm.bottom) |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Default event handler for the <code>scroll</code> event. |
| * |
| * @param event The event object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function scrollHandler(event:Event):void |
| { |
| // TextField.scroll bubbles so you might see it here |
| if (event is ScrollEvent) |
| { |
| var scrollBar:ScrollBar = ScrollBar(event.target); |
| |
| var pos:Number = scrollBar.scrollPosition; |
| |
| var prop:QName; |
| if (scrollBar == verticalScrollBar) |
| prop = new QName(mx_internal, "_verticalScrollPosition"); |
| else if (scrollBar == horizontalScrollBar) |
| prop = new QName(mx_internal, "_horizontalScrollPosition"); |
| |
| dispatchEvent(event); |
| |
| if (prop) |
| this[prop] = pos; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function scrollTipHandler(event:Event):void |
| { |
| // TextField.scroll bubbles so you might see it here |
| if (event is ScrollEvent) |
| { |
| if (!showScrollTips) |
| return; |
| |
| if (ScrollEvent(event).detail == ScrollEventDetail.THUMB_POSITION) |
| { |
| if (scrollTip) |
| { |
| ToolTipManager.destroyToolTip(scrollTip); |
| scrollTip = null; |
| ToolTipManager.enabled = oldTTMEnabled; |
| } |
| } |
| else if (ScrollEvent(event).detail == ScrollEventDetail.THUMB_TRACK) |
| { |
| var scrollBar:ScrollBar = ScrollBar(event.target); |
| var isVertical:Boolean = scrollBar == verticalScrollBar; |
| var dir:String = isVertical ? "vertical" : "horizontal"; |
| var pos:Number = scrollBar.scrollPosition; |
| |
| if (!scrollTip) |
| { |
| scrollTip = ToolTipManager.createToolTip("", 0, 0, null, this); |
| scrollThumbMidPoint = scrollBar.scrollThumb.height / 2; |
| oldTTMEnabled = ToolTipManager.enabled; |
| ToolTipManager.enabled = false; |
| } |
| |
| var tip:String = pos.toString(); |
| |
| if (_scrollTipFunction != null) |
| tip = _scrollTipFunction(dir, pos); |
| |
| if (tip == "") |
| { |
| scrollTip.visible = false; |
| } |
| else |
| { |
| scrollTip.text = tip; |
| |
| ToolTipManager.sizeTip(scrollTip); |
| |
| var pt:Point = new Point(); |
| if (isVertical) |
| { |
| pt.x = -3 - scrollTip.width; |
| pt.y = scrollBar.scrollThumb.y + scrollThumbMidPoint - |
| scrollTip.height / 2; |
| } |
| else |
| { |
| // The scrollbar is rotated so we kind of reverse things |
| // around with width and height. |
| pt.x = -3 - scrollTip.height; |
| pt.y = scrollBar.scrollThumb.y + scrollThumbMidPoint - |
| scrollTip.width / 2; |
| } |
| pt = scrollBar.localToGlobal(pt); |
| scrollTip.move(pt.x, pt.y); |
| |
| scrollTip.visible = true; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Event handler for the mouse wheel scroll event. |
| * |
| * @param event The event object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function mouseWheelHandler(event:MouseEvent):void |
| { |
| // If this Container has a vertical scrollbar, |
| // then handle the event and prevent further bubbling. |
| if (verticalScrollBar && verticalScrollBar.visible && !event.isDefaultPrevented()) |
| { |
| var scrollDirection:int = event.delta <= 0 ? 1 : -1; |
| |
| // Make sure we scroll by at least one line |
| var scrollAmount:Number = Math.max(Math.abs(event.delta), |
| verticalScrollBar.lineScrollSize); |
| |
| // Multiply by 3 to make scrolling a little faster |
| var oldPosition:Number = verticalScrollPosition; |
| verticalScrollPosition += 3 * scrollAmount * scrollDirection; |
| |
| var scrollEvent:ScrollEvent = new ScrollEvent(ScrollEvent.SCROLL); |
| scrollEvent.direction = ScrollEventDirection.VERTICAL; |
| scrollEvent.position = verticalScrollPosition; |
| scrollEvent.delta = verticalScrollPosition - oldPosition; |
| dispatchEvent(scrollEvent); |
| |
| event.preventDefault(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function get scroll_verticalScrollBar():ScrollBar |
| { |
| return verticalScrollBar; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function get scroll_horizontalScrollBar():ScrollBar |
| { |
| return horizontalScrollBar; |
| } |
| } |
| } |