You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by al...@apache.org on 2018/05/28 06:40:06 UTC
[royale-asjs] branch feature/MXRoyale updated: Scroller.as Added
This is an automated email from the ASF dual-hosted git repository.
alinakazi pushed a commit to branch feature/MXRoyale
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
The following commit(s) were added to refs/heads/feature/MXRoyale by this push:
new ecc0e14 Scroller.as Added
ecc0e14 is described below
commit ecc0e145cc6e8fcfe9ab90b7120e89ac0ed46530
Author: alinakazi <AL...@GMAIL.COM>
AuthorDate: Mon May 28 11:39:42 2018 +0500
Scroller.as Added
---
.../src/main/royale/spark/components/Scroller.as | 3864 ++++++++++++++++++++
1 file changed, 3864 insertions(+)
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Scroller.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Scroller.as
new file mode 100644
index 0000000..f0ae6d9
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Scroller.as
@@ -0,0 +1,3864 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package spark.components
+{
+/* import flash.display.DisplayObject;
+import flash.events.Event;
+import flash.events.FocusEvent;
+import flash.events.KeyboardEvent;
+import flash.events.MouseEvent;
+import flash.events.SoftKeyboardEvent;
+import flash.events.TimerEvent;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.system.Capabilities;
+import flash.text.TextField;
+import flash.ui.Keyboard;
+import flash.utils.Timer; */
+
+/* import mx.core.EventPriority;
+import mx.core.FlexGlobals;
+import mx.core.IFactory;
+import mx.core.IInvalidating;
+import mx.core.InteractionMode;
+import mx.core.LayoutDirection;
+import mx.core.UIComponent;
+import mx.events.EffectEvent;
+import mx.events.FlexEvent;
+import mx.events.FlexMouseEvent;
+import mx.events.PropertyChangeEvent;
+import mx.events.TouchInteractionEvent;
+import mx.managers.IFocusManager;
+import mx.styles.IStyleClient;
+
+import spark.components.supportClasses.GroupBase;
+import spark.components.supportClasses.ScrollerLayout;
+import spark.components.supportClasses.TouchScrollHelper;
+import spark.core.IGraphicElement;
+import spark.core.IViewport;
+import spark.core.NavigationUnit;
+import spark.effects.Animate;
+import spark.effects.ThrowEffect;
+import spark.effects.animation.MotionPath;
+import spark.effects.animation.SimpleMotionPath;
+import spark.events.CaretBoundsChangeEvent;
+import spark.layouts.supportClasses.LayoutBase;
+import spark.utils.MouseEventUtil; */
+import mx.core.IVisualElement;
+import mx.core.mx_internal;
+import spark.components.supportClasses.SkinnableComponent;
+import mx.core.IVisualElementContainer;
+import mx.managers.IFocusManagerComponent;
+
+import org.apache.royale.events.Event;
+
+use namespace mx_internal;
+/*
+include "../styles/metadata/BasicInheritingTextStyles.as"
+include "../styles/metadata/AdvancedInheritingTextStyles.as"
+include "../styles/metadata/SelectionFormatTextStyles.as"
+ */
+//--------------------------------------
+// Events
+//--------------------------------------
+
+/**
+ * Dispatched when the scroll position is going to change due to a
+ * <code>mouseWheel</code> event.
+ *
+ * <p>If there is a visible verticalScrollBar, then by default
+ * the viewport is scrolled vertically by <code>event.delta</code> "steps".
+ * The height of the step is determined by the viewport's
+ * <code>getVerticalScrollPositionDelta</code> method using
+ * either <code>UP</code> or <code>DOWN</code>, depending on the scroll
+ * direction.</p>
+ *
+ * <p>Otherwise, if there is a visible horizontalScrollBar, then by default
+ * the viewport is scrolled horizontally by <code>event.delta</code> "steps".
+ * The width of the step is determined by the viewport's
+ * <code>getHorizontalScrollPositionDelta</code> method using
+ * either <code>LEFT</code> or <code>RIGHT</code>, depending on the scroll
+ * direction.</p>
+ *
+ * <p>Calling the <code>preventDefault()</code> method
+ * on the event prevents the scroll position from changing.
+ * Otherwise if you modify the <code>delta</code> property of the event,
+ * that value will be used as the number of "steps".</p>
+ *
+ * @eventType mx.events.FlexMouseEvent.MOUSE_WHEEL_CHANGING
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+//[Event(name="mouseWheelChanging", type="mx.events.FlexMouseEvent")]
+
+//--------------------------------------
+// Styles
+//--------------------------------------
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:alternatingItemColors
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="alternatingItemColors", type="Array", arrayType="uint", format="Color", inherit="yes", theme="spark, mobile")]
+
+/**
+ * The alpha of the content background for this component.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="contentBackgroundAlpha", type="Number", inherit="yes", theme="spark, mobile")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:contentBackgroundColor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="contentBackgroundColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:downColor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.1
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="downColor", type="uint", format="Color", inherit="yes", theme="mobile")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:focusColor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="focusColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")]
+
+/**
+ * Indicates under what conditions the horizontal scroll bar is displayed.
+ *
+ * <ul>
+ * <li>
+ * <code>ScrollPolicy.ON</code> ("on") - the scroll bar is always displayed.
+ * </li>
+ * <li>
+ * <code>ScrollPolicy.OFF</code> ("off") - the scroll bar is never displayed.
+ * The viewport can still be scrolled programmatically, by setting its
+ * horizontalScrollPosition property.
+ * </li>
+ * <li>
+ * <code>ScrollPolicy.AUTO</code> ("auto") - the scroll bar is displayed when
+ * the viewport's contentWidth is larger than its width.
+ * </li>
+ * </ul>
+ *
+ * <p>
+ * The scroll policy affects the measured size of the Scroller component.
+ * </p>
+ *
+ * @default ScrollPolicy.AUTO
+ *
+ * @see mx.core.ScrollPolicy
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+[Style(name="horizontalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]
+
+/**
+ * A proxy for the <code>liveDragging</code> style of the scrollbars
+ * used by the Scroller component.
+ *
+ * <p>If this style is set to <code>true</code>, then the
+ * <code>liveDragging</code> styles are set to <code>true</code> (the default).
+ * That means dragging a scrollbar thumb immediately updates the viewport's scroll position.
+ * If this style is set to <code>false</code>, then the <code>liveDragging</code> styles
+ * are set to <code>false</code>.
+ * That means when a scrollbar thumb is dragged the viewport's scroll position is only updated
+ * then the mouse button is released.</p>
+ *
+ * <p>Setting this style to <code>false</code> can be helpful
+ * when updating the viewport's display is so
+ * expensive that "liveDragging" performs poorly.</p>
+ *
+ * <p>By default this style is <code>undefined</code>, which means that
+ * the <code>liveDragging</code> styles are not modified.</p>
+ *
+ * @default undefined
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="liveScrolling", type="Boolean", inherit="no")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:rollOverColor
+ *
+ * @default 0xCEDBEF
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="rollOverColor", type="uint", format="Color", inherit="yes", theme="spark")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:symbolColor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")]
+
+/**
+ * @copy spark.components.supportClasses.GroupBase#style:touchDelay
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.1
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="touchDelay", type="Number", format="Time", inherit="yes", minValue="0.0")]
+
+/**
+ * Indicates under what conditions the vertical scroll bar is displayed.
+ *
+ * <ul>
+ * <li>
+ * <code>ScrollPolicy.ON</code> ("on") - the scroll bar is always displayed.
+ * </li>
+ * <li>
+ * <code>ScrollPolicy.OFF</code> ("off") - the scroll bar is never displayed.
+ * The viewport can still be scrolled programmatically, by setting its
+ * verticalScrollPosition property.
+ * </li>
+ * <li>
+ * <code>ScrollPolicy.AUTO</code> ("auto") - the scroll bar is displayed when
+ * the viewport's contentHeight is larger than its height.
+ * </li>
+ * </ul>
+ *
+ * <p>
+ * The scroll policy affects the measured size of the Scroller component.
+ * </p>
+ *
+ * @default ScrollPolicy.AUTO
+ *
+ * @see mx.core.ScrollPolicy
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+//[Style(name="verticalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]
+
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("components")]
+
+[DefaultProperty("viewport")]
+
+//[IconFile("Scroller.png")]
+
+/**
+ * The Scroller component displays a single scrollable component,
+ * called a viewport, and horizontal and vertical scroll bars.
+ * The viewport must implement the IViewport interface. Its skin
+ * must be a derivative of the Group class.
+ *
+ * <p>The Spark Group, DataGroup, and RichEditableText components implement
+ * the IViewport interface and can be used as the children of the Scroller control,
+ * as the following example shows:</p>
+ *
+ * <pre>
+ * <s:Scroller width="100" height="100">
+ * <s:Group>
+ * <mx:Image width="300" height="400"
+ * source="@Embed(source='assets/logo.jpg')"/>
+ * </s:Group>
+ * </s:Scroller></pre>
+ *
+ * <p>The size of the Image control is set larger than that of its parent Group container.
+ * By default, the child extends past the boundaries of the parent container.
+ * Rather than allow the child to extend past the boundaries of the parent container,
+ * the Scroller specifies to clip the child to the boundaries and display scroll bars.</p>
+ *
+ * <p>Not all Spark containers implement the IViewPort interface.
+ * Therefore, those containers, such as the BorderContainer and SkinnableContainer containers,
+ * cannot be used as the direct child of the Scroller component.
+ * However, all Spark containers can have a Scroller component as a child component.
+ * For example, to use scroll bars on a child of the Spark BorderContainer,
+ * wrap the child in a Scroller component. </p>
+ *
+ * <p>To make the entire BorderContainer scrollable, wrap it in a Group container.
+ * Then, make the Group container the child of the Scroller component,
+ * For skinnable Spark containers that do not implement the IViewport interface,
+ * you can also create a custom skin for the container that
+ * includes the Scroller component. </p>
+ *
+ * <p>The IViewport interface defines a viewport for the components that implement it.
+ * A viewport is a rectangular subset of the area of a container that you want to display,
+ * rather than displaying the entire container.
+ * The scroll bars control the viewport's <code>horizontalScrollPosition</code> and
+ * <code>verticalScrollPosition</code> properties.
+ * scroll bars make it possible to view the area defined by the viewport's
+ * <code>contentWidth</code> and <code>contentHeight</code> properties.</p>
+ *
+ * <p>You can directly set properties on the component wrapped by the Scroller by
+ * using the <code>Scroller.viewport</code> property.
+ * For example, you can modify the viewport's <code>horizontalScrollPosition</code> and
+ * <code>verticalScrollPosition</code> properties.</p>
+ *
+ * <p>To directly access the scroll bar instances, either HScrollBar or VScrollBar,
+ * created by the Scroller, use the <code>Scroller.horizontalScrollBar</code> and
+ * <code>Scroller.verticalScrollBar</code> properties.</p>
+ *
+ * <p>You can combine scroll bars with explicit settings for the container's viewport.
+ * The viewport settings determine the initial position of the viewport,
+ * and then you can use the scroll bars to move it, as the following example shows: </p>
+ *
+ * <pre>
+ * <s:Scroller width="100" height="100">
+ * <s:Group
+ * horizontalScrollPosition="50" verticalScrollPosition="50">
+ * <mx:Image width="300" height="400"
+ * source="@Embed(source='assets/logo.jpg')"/>
+ * </s:Group>
+ * </s:Scroller></pre>
+ *
+ * <p>The scroll bars are displayed according to the vertical and horizontal scroll bar
+ * policy, which can be <code>auto</code>, <code>on</code>, or <code>off</code>.
+ * The <code>auto</code> policy means that the scroll bar will be visible and included
+ * in the layout when the viewport's content is larger than the viewport itself.</p>
+ *
+ * <p>The Scroller skin layout cannot be changed. It is unconditionally set to a
+ * private layout implementation that handles the scroll policies. Scroller skins
+ * can only provide replacement scroll bars. To gain more control over the layout
+ * of a viewport and its scroll bars, instead of using Scroller, just add them
+ * to a <code>Group</code> and use the scroll bar <code>viewport</code> property
+ * to link them together.</p>
+ *
+ * <p>The Scroller control has the following default characteristics:</p>
+ * <table class="innertable">
+ * <tr>
+ * <th>Characteristic</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>Default size</td>
+ * <td>0</td>
+ * </tr>
+ * <tr>
+ * <td>Minimum size</td>
+ * <td>0</td>
+ * </tr>
+ * <tr>
+ * <td>Maximum size</td>
+ * <td>10000 pixels wide and 10000 pixels high</td>
+ * </tr>
+ * <tr>
+ * <td>Default skin class</td>
+ * <td>spark.skins.spark.ScrollerSkin</td>
+ * </tr>
+ * </table>
+ *
+ * @mxml
+ *
+ * <p>The <code><s:Scroller></code> tag inherits all of the tag
+ * attributes of its superclass and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:Scroller
+ * <strong>Properties</strong>
+ * measuredSizeIncludesScrollBars="true"
+ * minViewportInset="0"
+ * pageScrollingEnabled="false"
+ * scrollSnappingMode="none"
+ * viewport="null"
+ *
+ * <strong>Styles</strong>
+ * alignmentBaseline="use_dominant_baseline"
+ * alternatingItemColors=""
+ * baselineShift="0.0"
+ * blockProgression="TB"
+ * breakOpportunity="auto"
+ * cffHinting="horizontal_stem"
+ * clearFloats="none"
+ * color="0"
+ * contentBackgroundAlpha=""
+ * contentBackgroundColor=""
+ * digitCase="default"
+ * digitWidth="default"
+ * direction="LTR"
+ * dominantBaseline="auto"
+ * downColor=""
+ * firstBaselineOffset="auto"
+ * focusColor=""
+ * focusedTextSelectionColor=""
+ * fontFamily="Arial"
+ * fontLookup="device"
+ * fontSize="12"
+ * fontStyle="normal"
+ * fontWeight="normal"
+ * horizontalScrollPolicy="auto"
+ * inactiveTextSelection=""
+ * 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=""
+ * symbolColor=""
+ * tabStops="null"
+ * textAlign="start"
+ * textAlignLast="start"
+ * textAlpha="1"
+ * textDecoration="none"
+ * textIndent="0"
+ * textJustify="inter_word"
+ * textRotation="auto"
+ * trackingLeft="0"
+ * trackingRight="0"
+ * typographicCase="default"
+ * unfocusedTextSelectionColor=""
+ * verticalScrollPolicy="auto"
+ * whiteSpaceCollapse="collapse"
+ * wordSpacing="100%,50%,150%"
+ * />
+ * </pre>
+ *
+ * @see spark.core.IViewport
+ * @see spark.components.DataGroup
+ * @see spark.components.Group
+ * @see spark.components.RichEditableText
+ * @see spark.skins.spark.ScrollerSkin
+ *
+ * @includeExample examples/ScrollerExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+
+public class Scroller extends SkinnableComponent
+ implements IFocusManagerComponent, IVisualElementContainer
+{
+ //include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * The ratio that determines how far the list scrolls when pulled past its end.
+ */
+ // private static const PULL_TENSION_RATIO:Number = 0.5;
+
+ /**
+ * @private
+ * Used so we don't have to keep allocating Point(0,0) to do coordinate conversions
+ * while draggingg
+ */
+ //private static const ZERO_POINT:Point = new Point(0,0);
+
+ /**
+ * @private
+ * The name of the viewport's horizontal scroll position property
+ */
+ // private static const HORIZONTAL_SCROLL_POSITION:String = "horizontalScrollPosition";
+
+ /**
+ * @private
+ * The name of the viewport's vertical scroll position property
+ */
+ // private static const VERTICAL_SCROLL_POSITION:String = "verticalScrollPosition";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ public function Scroller()
+ {
+ super();
+ /* hasFocusableChildren = true;
+ focusEnabled = false;
+
+ addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+ addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); */
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables: Touch Scrolling
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Threshold for screen distance they must move to count as a scroll
+ * Based on 20 pixels on a 252ppi device.
+ */
+ // mx_internal var minSlopInches:Number = 0.079365; // 20.0/252.0
+
+ /**
+ * @private
+ * The amount of deceleration to apply to the velocity for each effect period
+ * For a faster deceleration, you can switch this to 0.990.
+ */
+ // mx_internal var throwEffectDecelFactor:Number = 0.998;
+
+ /**
+ * @private
+ * When pageScrollingEnabled is true, this var specifies the minimum distance
+ * (as a percentage of the viewport size) that the content needs to be dragged
+ * in order to switch to an adjacent page.
+ */
+ // mx_internal var pageDragDistanceThreshold:Number = 0.5;
+
+ /**
+ * @private
+ * When pageScrollingEnabled is true, this var specifies the minimum velocity
+ * (in inches/second) that a throw needs in order to switch to an adjacent page.
+ */
+ // mx_internal var pageThrowVelocityThreshold:Number = 0.8;
+
+ /**
+ * @private
+ */
+ // private var scrollRangesChanged:Boolean = false;
+
+ /**
+ * @private
+ */
+ // private var pageScrollingChanged:Boolean = false;
+
+ /**
+ * @private
+ */
+ // private var snappingModeChanged:Boolean = false;
+
+ /**
+ * @private
+ */
+ // private var _pullEnabled:Boolean = true;
+
+ /**
+ * @private
+ */
+ /* mx_internal function get pullEnabled():Boolean
+ {
+ return _pullEnabled;
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function set pullEnabled(value:Boolean):void
+ {
+ if (_pullEnabled == value)
+ return;
+
+ _pullEnabled = value;
+ scrollRangesChanged = true;
+ invalidateProperties();
+ } */
+
+ /**
+ * @private
+ */
+ // private var _bounceEnabled:Boolean = true;
+
+ /**
+ * @private
+ */
+ /* mx_internal function get bounceEnabled():Boolean
+ {
+ return _bounceEnabled;
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function set bounceEnabled(value:Boolean):void
+ {
+ if (_bounceEnabled == value)
+ return;
+
+ _bounceEnabled = value;
+ scrollRangesChanged = true;
+ invalidateProperties();
+ } */
+
+
+ /**
+ * @private
+ * Touch Scroll Helper -- used to help figure out
+ * scrolling velocity and other information
+ */
+ // private var touchScrollHelper:TouchScrollHelper;
+
+ /**
+ * @private
+ * Keeps track of the horizontal scroll position
+ * before scrolling started, so we can figure out
+ * how to related it to the dragX that are
+ * associated with the touchScrollDrag events.
+ */
+ // private var hspBeforeTouchScroll:Number;
+
+ /**
+ * @private
+ * Keeps track of the vertical scroll position
+ * before scrolling started, so we can figure out
+ * how to related it to the dragY that are
+ * associated with the touchScrollDrag events.
+ */
+ // private var vspBeforeTouchScroll:Number;
+
+ /**
+ * @private
+ * Effect used for touch scroll throwing
+ */
+ // mx_internal var throwEffect:ThrowEffect;
+
+ /**
+ * @private
+ * The final position in the throw effect's vertical motion path
+ */
+ // private var throwFinalVSP:Number;
+
+ /**
+ * @private
+ * The final position in the throw effect's horizontal motion path
+ */
+ // private var throwFinalHSP:Number;
+
+ /**
+ * @private
+ * Indicates whether the previous throw reached one of the maximum
+ * scroll positions (vsp or hsp) that was in effect at the time.
+ */
+ // private var throwReachedMaximumScrollPosition:Boolean;
+
+ /**
+ * @private
+ * Used to keep track of whether the throw animation
+ * was stopped pre-emptively. We stop propogation of
+ * the mouse event, but in the throwEffect.EFFECT_END
+ * event handler, we need to tell it not to exit the
+ * scrolling state.
+ */
+ // private var stoppedPreemptively:Boolean = false;
+
+ /**
+ * @private
+ * Used to keep track of whether we should capture the next
+ * click event that we receive or whether we should let it dispatch
+ * normally. We capture the click event if a scroll happened. We
+ * set this property in mouseDown and touchScrollStart.
+ */
+ // private var captureNextClick:Boolean = false;
+
+ /**
+ * @private
+ * Used to keep track of whether we should capture the next
+ * mousedown event that we receive or whether we should let it dispatch
+ * normally. We capture the mousedown event if a scroll-throw is
+ * currently happening. We set this property in mouseDown, touchInteractionStart,
+ * and touchInteractionEnd.
+ */
+ // private var captureNextMouseDown:Boolean = false;
+
+ /**
+ * @private
+ * Animation to fade the scrollbars out when we are done
+ * throwing or dragging
+ */
+ // private var hideScrollBarAnimation:Animate;
+
+ /**
+ * @private
+ * Use to figure out whether the animation ended naturally and finished or
+ * whether we called stop() on it. Unfortunately, we get an EFFECT_END in
+ * both cases, so we must keep track of it ourselves.
+ */
+ // private var hideScrollBarAnimationPrematurelyStopped:Boolean;
+
+ /**
+ * @private
+ * Keeps track of whether a touch interaction is in progress.
+ */
+ // mx_internal var inTouchInteraction:Boolean = false;
+
+
+ /**
+ * @private
+ * These are the minimum and maximum scroll positions allowed
+ * for both axes. They determine the points at which bounce and
+ * pull occur.
+ */
+ /* private var minVerticalScrollPosition:Number = 0;
+ private var maxVerticalScrollPosition:Number = 0;
+ private var minHorizontalScrollPosition:Number = 0;
+ private var maxHorizontalScrollPosition:Number = 0;
+ */
+ /**
+ * @private
+ * The animation used by the snapElement function.
+ */
+ // private var snapElementAnimation:Animate;
+
+ /**
+ * @private
+ * When pageScrollingEnabled is true, this contains the
+ * scroll position of the current page.
+ */
+ // private var currentPageScrollPosition:Number;
+
+
+ /**
+ * @private
+ * Keeps track of the most recently snapped item, or -1 if none.
+ * This value is set as a side-effect of calling getSnappedPosition.
+ */
+ // private var lastSnappedElement:int = -1;
+
+ /**
+ * @private
+ * Remembers which part of the content is snapped at the
+ * time an orientation change begins. For paging without
+ * item snapping, this value is a page number. For item
+ * snapping, the value is an element number.
+ */
+ // private var orientationChangeSnapElement:int = -1;
+
+ /**
+ * @private
+ * Remembers the number of pages right before an orientation
+ * change occurs.
+ */
+ // private var previousOrientationPageCount:int = 0;
+
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables: SoftKeyboard Support
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * Some devices do not support a hardware keyboard.
+ * Instead, these devices use a keyboard that opens on
+ * the screen when necessary.
+ * A value of <code>true</code> means that when a component in
+ * the container wrapped by the scroller receives focus,
+ * the Scroller scrolls that component into view if the keyboard is
+ * opening
+ */
+ // mx_internal var ensureElementIsVisibleForSoftKeyboard:Boolean = true;
+
+ /**
+ * @private
+ */
+ // private var lastFocusedElement:IVisualElement;
+
+ /**
+ * @private
+ * Used to detect when the device orientation (landscape/portrait) has changed
+ */
+ // private var aspectRatio:String;
+
+ /**
+ * @private
+ */
+ // private var oldSoftKeyboardHeight:Number = NaN;
+
+ /**
+ * @private
+ */
+ // private var oldSoftKeyboardWidth:Number = NaN;
+
+ /**
+ * @private
+ */
+ // mx_internal var preventThrows:Boolean = false;
+
+ /**
+ * @private
+ */
+ // private var lastFocusedElementCaretBounds:Rectangle;
+
+ /**
+ * @private
+ */
+ // private var captureNextCaretBoundsChange:Boolean = false;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // horizontalScrollBar
+ //----------------------------------
+
+ //[SkinPart(required="false")]
+ // [Bindable]
+
+ /**
+ * A skin part that defines the horizontal scroll bar.
+ *
+ * This property should be considered read-only. It is only
+ * set by the Scroller's skin.
+ *
+ * This property is Bindable.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ //public var horizontalScrollBar:HScrollBar;
+
+ //----------------------------------
+ // horizontalScrollBarFactory
+ //----------------------------------
+
+ //[SkinPart(required="false", type="spark.components.HScrollBar")]
+
+ /**
+ * A skin part that defines the horizontal scroll bar component.
+ *
+ * The <code>horizontalScrollBar</code> skin part takes precedence over this
+ * skin part.
+ *
+ * When Scroller creates an instance of this part, it will set the
+ * <code>horizontalScrollBar</code> skin part to that instance.
+ *
+ * This property should be considered read-only. It is only
+ * set by the Scroller's skin.
+ * To access the HScrollBar instance, use <code>horizontalScrollBar</code>.
+ */
+ // public var horizontalScrollBarFactory:IFactory;
+
+ /**
+ * Creates the horizontalScrollBar part from the horizontalScrollBarFactory part.
+ */
+ /* private function ensureDeferredHScrollBarCreated():void
+ {
+ if (!horizontalScrollBar && horizontalScrollBarFactory)
+ {
+ horizontalScrollBar = HScrollBar(createDynamicPartInstance("horizontalScrollBarFactory"));
+ Group(this.skin).addElement(horizontalScrollBar);
+ partAdded("horizontalScrollBar", horizontalScrollBar);
+ }
+ } */
+
+ //----------------------------------
+ // horizontalScrollInProgress
+ //----------------------------------
+
+ /**
+ * Storage for the horizontalScrollInProgress property
+ */
+ // private var _horizontalScrollInProgress:Boolean = false;
+
+ /**
+ * @private
+ * Property used to communicate with ScrollerLayout to let it
+ * know when a horizontal scroll is in progress or not (and when
+ * the horizontal scroll bar should be hidden or not)
+ */
+ /* mx_internal function get horizontalScrollInProgress():Boolean
+ {
+ return _horizontalScrollInProgress;
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function set horizontalScrollInProgress(value:Boolean):void
+ {
+ _horizontalScrollInProgress = value;
+ if (value && getStyle("interactionMode") == InteractionMode.TOUCH)
+ ensureDeferredHScrollBarCreated();
+ } */
+
+ //----------------------------------
+ // verticalScrollBar
+ //----------------------------------
+
+ /* [SkinPart(required="false")]
+ [Bindable] */
+
+ /**
+ * A skin part that defines the vertical scroll bar.
+ *
+ * This property should be considered read-only. It is only
+ * set by the Scroller's skin.
+ *
+ * This property is Bindable.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ //public var verticalScrollBar:VScrollBar;
+
+ //----------------------------------
+ // verticalScrollBarFactory
+ //----------------------------------
+
+ //[SkinPart(required="false", type="spark.components.VScrollBar")]
+
+ /**
+ * A skin part that defines the vertical scroll bar.
+ *
+ * The <code>verticalScrollBar</code> skin part takes precedence over this
+ * skin part.
+ *
+ * When Scroller creates an instance of this part, it will set the
+ * <code>verticalScrollBar</code> skin part to that instance.
+ *
+ * This property should be considered read-only. It is only
+ * set by the Scroller's skin.
+ * To access the VScrollBar instance, use <code>verticalScrollBar</code>.
+ */
+ //public var verticalScrollBarFactory:IFactory;
+
+ /**
+ * Creates the verticalScrollBar part from the verticalScrollBarFactory part.
+ */
+ /* private function ensureDeferredVScrollBarCreated():void
+ {
+ if (!verticalScrollBar && verticalScrollBarFactory)
+ {
+ verticalScrollBar = VScrollBar(createDynamicPartInstance("verticalScrollBarFactory"));
+ Group(this.skin).addElement(verticalScrollBar);
+ partAdded("verticalScrollBar", verticalScrollBar);
+ }
+ } */
+
+ //----------------------------------
+ // verticalScrollInProgress
+ //----------------------------------
+
+ /**
+ * Storage for the verticalScrollInProgress property
+ */
+ // private var _verticalScrollInProgress:Boolean = false;
+
+ /**
+ * @private
+ * Property used to communicate with ScrollerLayout to let it
+ * know when a vertical scroll is in progress or not (and when
+ * the vertical scroll bar should be hidden or not)
+ */
+ /* mx_internal function get verticalScrollInProgress():Boolean
+ {
+ return _verticalScrollInProgress;
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function set verticalScrollInProgress(value:Boolean):void
+ {
+ _verticalScrollInProgress = value;
+ if (value && getStyle("interactionMode") == InteractionMode.TOUCH)
+ ensureDeferredVScrollBarCreated();
+ } */
+
+ //----------------------------------
+ // viewport - default property
+ //----------------------------------
+
+ private var _viewport:IVisualElement;//IViewport;
+
+ [Bindable(event="viewportChanged")]
+
+ /**
+ * The viewport component to be scrolled.
+ *
+ * <p>
+ * The viewport is added to the Scroller component's skin,
+ * which lays out both the viewport and scroll bars.
+ *
+ * When the <code>viewport</code> property is set, the viewport's
+ * <code>clipAndEnableScrolling</code> property is
+ * set to true to enable scrolling.
+ *
+ * The Scroller does not support rotating the viewport directly. The viewport's
+ * contents can be transformed arbitrarily, but the viewport itself cannot.
+ * </p>
+ *
+ * This property is Bindable.
+ *
+ * @default null
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ public function get viewport(): IVisualElement//IViewport
+ {
+ return _viewport;
+ }
+
+ /**
+ * @private
+ */
+ public function set viewport(value:IVisualElement):void
+ {
+ if (value == _viewport)
+ return;
+
+ // uninstallViewport();
+ _viewport = value;
+ // installViewport();
+ dispatchEvent(new Event("viewportChanged"));
+ }
+
+ /**
+ * @private
+ * This is used to disable thinning for automated testing.
+ */
+ /* mx_internal static var dragEventThinning:Boolean = true;
+
+ private function installViewport():void
+ {
+ if (skin && viewport)
+ {
+ viewport.clipAndEnableScrolling = true;
+ Group(skin).addElementAt(viewport, 0);
+ viewport.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, viewport_propertyChangeHandler);
+ viewport.addEventListener(Event.RESIZE, viewport_resizeHandler);
+ }
+ if (verticalScrollBar)
+ verticalScrollBar.viewport = viewport;
+ if (horizontalScrollBar)
+ horizontalScrollBar.viewport = viewport;
+ }
+
+ private function uninstallViewport():void
+ {
+ if (horizontalScrollBar)
+ horizontalScrollBar.viewport = null;
+ if (verticalScrollBar)
+ verticalScrollBar.viewport = null;
+ if (skin && viewport)
+ {
+ viewport.clipAndEnableScrolling = false;
+ Group(skin).removeElement(viewport);
+ viewport.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, viewport_propertyChangeHandler);
+ viewport.removeEventListener(Event.RESIZE, viewport_resizeHandler);
+ }
+ }
+ */
+
+ //----------------------------------
+ // minViewportInset
+ //----------------------------------
+
+ private var _minViewportInset:Number = 0;
+
+ [Inspectable(category="General", defaultValue="0")]
+
+ /**
+ * The minimum space between the viewport and the edges of the Scroller.
+ *
+ * If neither of the scroll bars is visible, then the viewport is inset by
+ * <code>minViewportInset</code> on all four sides.
+ *
+ * If a scroll bar is visible then the viewport is inset by <code>minViewportInset</code>
+ * or by the scroll bar's size, whichever is larger.
+ *
+ * ScrollBars are laid out flush with the edges of the Scroller.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+ public function get minViewportInset():Number
+ {
+ return _minViewportInset;
+ }
+
+ /**
+ * @private
+ */
+ public function set minViewportInset(value:Number):void
+ {
+ if (value == _minViewportInset)
+ return;
+
+ _minViewportInset = value;
+ // invalidateSkin();
+ }
+
+ //----------------------------------
+ // measuredSizeIncludesScrollBars
+ //----------------------------------
+
+ private var _measuredSizeIncludesScrollBars:Boolean = true;
+
+ [Inspectable(category="General", defaultValue="true")]
+
+ /**
+ * If <code>true</code>, the Scroller's measured size includes the space required for
+ * the visible scroll bars, otherwise the Scroller's measured size depends
+ * only on its viewport.
+ *
+ * <p>Components like TextArea, which "reflow" their contents to fit the
+ * available width or height may use this property to stabilize their
+ * measured size. By default a TextArea's is defined by its <code>widthInChars</code>
+ * and <code>heightInChars</code> properties and in many applications it's preferable
+ * for the measured size to remain constant, event when scroll bars are displayed
+ * by the TextArea skin's Scroller.</p>
+ *
+ * <p>In components where the content does not reflow, like a typical List's
+ * items, the default behavior is preferable because it makes it less
+ * likely that the component's content will be obscured by a scroll bar.</p>
+ *
+ * @default true
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+ public function get measuredSizeIncludesScrollBars():Boolean
+ {
+ return _measuredSizeIncludesScrollBars;
+ }
+
+ /**
+ * @private
+ */
+ public function set measuredSizeIncludesScrollBars(value:Boolean):void
+ {
+ if (value == _measuredSizeIncludesScrollBars)
+ return;
+
+ _measuredSizeIncludesScrollBars = value;
+ // invalidateSkin();
+ }
+
+ //----------------------------------
+ // pageScrollingEnabled
+ //----------------------------------
+
+ /* private var _pageScrollingEnabled:Boolean = false;
+
+ [Inspectable(category="General", defaultValue="false")] */
+
+ /**
+ * By default, for mobile applications, scrolling is pixel based.
+ * The final scroll location is any pixel location based on
+ * the drag and throw gesture.
+ * Set <code>pageScrollingEnabled</code> to <code>true</code> to
+ * enable page scrolling.
+ *
+ * <p><b>Note: </b>This property is only valid when the <code>interactionMode</code> style
+ * is set to <code>touch</code>, indicating a mobile application.</p>
+ *
+ * <p>The size of the page is determined by the size of the viewport
+ * of the scrollable component.
+ * You can only scroll a single page at a time, regardless of the scroll gesture.</p>
+ *
+ * <p>You must scroll at least 50% of the visible area of the component
+ * to cause the page to change.
+ * If you scroll less than 50%, the component remains on the current page.
+ * Alternatively, if the velocity of the scroll is high enough, the next page display.
+ * If the velocity is not high enough, the component remains on the current page.</p>
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Royale 0.9.4
+ */
+ /* public function get pageScrollingEnabled():Boolean
+ {
+ return _pageScrollingEnabled;
+ } */
+
+ /**
+ * @private
+ */
+ /* public function set pageScrollingEnabled(value:Boolean):void
+ {
+ if (value == _pageScrollingEnabled)
+ return;
+
+ _pageScrollingEnabled = value;
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ if (canScrollHorizontally && canScrollVertically)
+ throw new Error(resourceManager.getString("components", "operationSupportedForOneAxisOnly"));
+
+ scrollRangesChanged = true;
+ pageScrollingChanged = true;
+ invalidateProperties();
+ }
+ }
+ */
+ //----------------------------------
+ // scrollSnappingMode
+ //----------------------------------
+
+ /* private var _scrollSnappingMode:String = ScrollSnappingMode.NONE;
+
+ [Inspectable(category="General", enumeration="none,leadingEdge,center,trailingEdge", defaultValue="none")]
+ */
+ /**
+ * By default, for mobile applications, scrolling is pixel based.
+ * The final scroll location is any pixel location based on
+ * the drag and throw gesture.
+ * Set <code>scrollSnappingMode</code> to other than <code>none</code> to
+ * enable scroll snapping.
+ * With scroll snapping enabled,
+ * the content snaps to a final position based on the value of <code>scrollSnappingMode</code>.
+ *
+ * <p><b>Note: </b>This property is only valid when the <code>interactionMode</code> style
+ * is set to <code>touch</code>, indicating a mobile application.</p>
+ *
+ * <p>For example, you scroll a List vertically with <code>scrollSnappingMode</code>
+ * set to a value of <code>leadingEdge</code>.
+ * The List control snaps to a final scroll position where the top list element
+ * is aligned to the top of the list.</p>
+ *
+ * <p>Changing this property to anything other than <code>none</code> can
+ * result in an immediate change in scroll position to ensure
+ * an element is correctly snapped into position.
+ * This change in scroll position is not animated</p>
+ *
+ * <p>in MXML, the possible values are <code>"leadingEdge"</code>, <code>"center"</code>,
+ * <code>"trailingEdge"</code>, and <code>"none"</code>.
+ * ActionScript values are defined by spark.components.ScrollSnappingMode. </p>
+ *
+ * @see spark.components.ScrollSnappingMode
+ *
+ * @default "none"
+ *
+ * @langversion 3.0
+ * @playerversion AIR 3
+ * @productversion Royale 0.9.4
+ */
+ /* public function get scrollSnappingMode():String
+ {
+ return _scrollSnappingMode;
+ } */
+
+ /**
+ * @private
+ */
+ /* public function set scrollSnappingMode(value:String):void
+ {
+ if (value == _scrollSnappingMode)
+ return;
+
+ _scrollSnappingMode = value;
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ if (canScrollHorizontally && canScrollVertically)
+ throw new Error(resourceManager.getString("components", "operationSupportedForOneAxisOnly"));
+
+ scrollRangesChanged = true;
+ snappingModeChanged = true;
+ invalidateProperties();
+ }
+ } */
+
+ //----------------------------------
+ // maxDragRate
+ //----------------------------------
+
+ /* private static var _maxDragRate:Number = 30;
+
+ [Inspectable(category="General", defaultValue="30")] */
+
+ /**
+ *
+ * Maximum number of times per second the scroll position
+ * and the display will be updated while dragging.
+ *
+ * @default 30
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+
+ /* public static function get maxDragRate():Number
+ {
+ return _maxDragRate;
+ }
+
+ public static function set maxDragRate(value:Number):void
+ {
+ _maxDragRate = value;
+ } */
+
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Scrolls the viewport so the specified element is visible.
+ *
+ * @param element A child element of the container,
+ * or of a nested container, wrapped by the Scroller.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function ensureElementIsVisible(element:IVisualElement):void
+ {
+ ensureElementPositionIsVisible(element);
+ } */
+
+ /**
+ * @private
+ *
+ * @param elementLocalBounds ensure that these bounds of the element are
+ * visible. The bounds are in the coordinate system of the element
+ * @param doValidateNow if true, call validateNow() at the end of the
+ * function
+ */
+ /* private function ensureElementPositionIsVisible(element:IVisualElement,
+ elementLocalBounds:Rectangle = null,
+ entireElementVisible:Boolean = true,
+ doValidateNow:Boolean = true):void
+ {
+ // First check that the element is a descendant
+ // If we are a GraphicElement, use the element's parent
+ var possibleDescendant:DisplayObject = element as DisplayObject;
+
+ if (element is IGraphicElement)
+ possibleDescendant = IGraphicElement(element).parent as DisplayObject;
+
+ if (!possibleDescendant || !contains(possibleDescendant))
+ return;
+
+ var layout:LayoutBase = viewportLayout;
+
+ if (layout)
+ {
+ // Before we change the scroll position, make sure there is
+ // no throw effect playing.
+ if (throwEffect && throwEffect.isPlaying)
+ {
+ throwEffect.stop();
+ snapContentScrollPosition();
+ }
+
+ // Scroll the element into view
+ var delta:Point = layout.getScrollPositionDeltaToAnyElement(element,
+ elementLocalBounds, entireElementVisible);
+
+ // Compute new delta if element is visible in the viewport bounds but is
+ // clipped/obscured by the soft keyboard
+ var topLevelApp:Application = FlexGlobals.topLevelApplication as Application;
+ var eltBounds:Rectangle;
+ var adjustForSoftKeyboard:Boolean = topLevelApp &&
+ (!topLevelApp.resizeForSoftKeyboard) &&
+ (stage && stage.softKeyboardRect.height > 0);
+
+ if (adjustForSoftKeyboard)
+ {
+ eltBounds = layout.getChildElementBounds(element);
+
+ // Get keyboard y-position in the scroller's coordinates
+ var keyboardTopLocal:Number = this.globalToLocal(stage.softKeyboardRect.topLeft).y;
+ var scrollerHeight:Number = this.getLayoutBoundsHeight();
+
+ // Does the keyboard clip the scroller?
+ // Is the bottom of the element clipped or outside the visible
+ // scroller height?
+ if ((keyboardTopLocal >= 0) &&
+ (keyboardTopLocal < scrollerHeight) &&
+ ((eltBounds.bottom - viewport.verticalScrollPosition) > keyboardTopLocal))
+ {
+ // Compute a new delta to accomodate the soft keyboard
+ var dy:Number = 0;
+
+ if (eltBounds.height > keyboardTopLocal)
+ {
+ // Top justify if the element is taller than the
+ // scroller's visible height
+ dy = eltBounds.top;
+ }
+ else
+ {
+ // Bottom justify the element
+ dy = eltBounds.bottom - keyboardTopLocal;
+ }
+
+ var dx:Number = (delta) ? delta.x : 0;
+
+ // account for current verticalScrollPosition
+ delta = new Point(dx, dy - viewport.verticalScrollPosition);
+ }
+ }
+
+ if (delta)
+ {
+ viewport.horizontalScrollPosition += delta.x;
+ viewport.verticalScrollPosition += delta.y;
+
+ // We only care about focusThickness if we are positioning the whole element
+ if (!elementLocalBounds)
+ {
+ if (!eltBounds)
+ eltBounds = layout.getChildElementBounds(element);
+
+ var focusThickness:Number = 0;
+
+ if (element is IStyleClient)
+ focusThickness = IStyleClient(element).getStyle("focusThickness");
+
+ // Make sure that the focus ring is visible. Top and left sides have priority
+ if (focusThickness)
+ {
+ if (viewport.verticalScrollPosition > eltBounds.top - focusThickness)
+ viewport.verticalScrollPosition = eltBounds.top - focusThickness;
+ else if (viewport.verticalScrollPosition + height < eltBounds.bottom + focusThickness)
+ viewport.verticalScrollPosition = eltBounds.bottom + focusThickness - height;
+
+ if (viewport.horizontalScrollPosition > eltBounds.left - focusThickness)
+ viewport.horizontalScrollPosition = eltBounds.left - focusThickness;
+ else if (viewport.horizontalScrollPosition + width < eltBounds.right + focusThickness)
+ viewport.horizontalScrollPosition = eltBounds.right + focusThickness - width;
+ }
+ }
+
+ if (doValidateNow && viewport is UIComponent)
+ UIComponent(viewport).validateNow();
+ }
+ }
+ } */
+
+ /**
+ * @private
+ * Internal API for programmatically snapping to a particular element.
+ * Can optionally animate the position change.
+ */
+ /* mx_internal function snapElement(elementIndex:int,animate:Boolean):Animate
+ {
+ var layout:LayoutBase = viewportLayout;
+ if (!layout)
+ throw new Error(resourceManager.getString("components", "operationRequiresViewportLayout"));
+
+ var elementBounds:Rectangle = layout.getElementBounds(elementIndex);
+ var snapScrollPosition:Number;
+
+ // Find the scroll position that puts the specified element into
+ // the appropriate snapped position.
+ switch (scrollSnappingMode)
+ {
+ case ScrollSnappingMode.NONE:
+ {
+ throw new Error(resourceManager.getString("components", "operationRequiresSnappingMode"));
+ }
+
+ case ScrollSnappingMode.LEADING_EDGE:
+ {
+ if (canScrollHorizontally)
+ snapScrollPosition = elementBounds.left;
+
+ else if (canScrollVertically)
+ snapScrollPosition = elementBounds.top;
+ break;
+ }
+ case ScrollSnappingMode.CENTER:
+ {
+ if (canScrollHorizontally)
+ snapScrollPosition = elementBounds.left + elementBounds.width/2 - viewport.width/2;
+ else if (canScrollVertically)
+ snapScrollPosition = elementBounds.top + elementBounds.height/2 - viewport.height/2;
+ break;
+ }
+ case ScrollSnappingMode.TRAILING_EDGE:
+ {
+ if (canScrollHorizontally)
+ snapScrollPosition = elementBounds.right - viewport.width;
+ else if (canScrollVertically)
+ snapScrollPosition = elementBounds.bottom - viewport.height;
+ break;
+ }
+ }
+
+ var scrollProperty:String;
+ if (canScrollHorizontally)
+ scrollProperty = HORIZONTAL_SCROLL_POSITION;
+ else if (canScrollVertically)
+ scrollProperty = VERTICAL_SCROLL_POSITION;
+
+ // If there's an animation playing, we need
+ // to stop it before we snap the element into
+ // position.
+ stopAnimations();
+
+ if (animate)
+ {
+ if (!snapElementAnimation)
+ {
+ snapElementAnimation = new Animate();
+ snapElementAnimation.duration = 300;
+ snapElementAnimation.target = viewport;
+ }
+ var snapMotionPath:Vector.<MotionPath> = Vector.<MotionPath>([new SimpleMotionPath(scrollProperty, null, snapScrollPosition)]);
+ snapElementAnimation.motionPaths = snapMotionPath;
+ snapElementAnimation.play();
+
+ // If paging is enabled, make sure the destination snap position
+ // also becomes the current page.
+ if (pageScrollingEnabled)
+ currentPageScrollPosition = snapScrollPosition;
+
+ return snapElementAnimation;
+ }
+ else
+ {
+ if (scrollProperty)
+ viewport[scrollProperty] = snapScrollPosition;
+
+ return null;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function stopAnimations():void
+ {
+ if (throwEffect && throwEffect.isPlaying)
+ throwEffect.stop();
+ if (snapElementAnimation && snapElementAnimation.isPlaying)
+ snapElementAnimation.stop();
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Event Handlers
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ /* private function getCurrentPageCount():int
+ {
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+
+ var pageCount:int = 0;
+
+ if (canScrollHorizontally && viewportWidth != 0)
+ {
+ pageCount = Math.ceil(viewport.contentWidth / viewportWidth);
+ }
+ else if (canScrollVertically && viewportHeight != 0)
+ {
+ pageCount = Math.ceil(viewport.contentHeight/ viewportHeight);
+ }
+
+ return pageCount;
+ } */
+
+ /**
+ * @private
+ */
+ /* private function checkScrollPosition():void
+ {
+ // TODO (eday): This function is a mess. It needs to be refactored and simplified.
+ // It does too many things and has too many subtle behaviors. But as I'm
+ // writing this we're too late in the release (4.6) schedule to make any
+ // changes of that size. This should be revisited during 5.0 development.
+
+ // If the content size has changed, we may need to recalculate
+ // the minimum and maximum scroll positions.
+ determineScrollRanges();
+
+ // Determine whether there's been a device orientation change
+ // Note: the first time this code runs it may falsely appear as though an orientation
+ // change has occurred (aspectRatio is null). This is okay since there will be no
+ // throw animation playing, so orientationChange will not be acted upon.
+ var orientationChange:Boolean = aspectRatio != FlexGlobals.topLevelApplication.aspectRatio;
+ aspectRatio = FlexGlobals.topLevelApplication.aspectRatio;
+
+ // See whether we possibly need to re-throw because of changed max positions.
+ var needRethrow:Boolean = false;
+
+ // Here we check to see whether the current throw has maybe not gone far enough
+ // given the new content size.
+ // We don't rethrow for this reason in paging mode, as we don't want to go any further
+ // than to the adjacent page.
+ if (!pageScrollingEnabled)
+ {
+ if (throwReachedMaximumScrollPosition && (throwFinalVSP < maxVerticalScrollPosition || throwFinalHSP < maxHorizontalScrollPosition))
+ needRethrow = true;
+
+ if (throwFinalVSP > maxVerticalScrollPosition || throwFinalHSP > maxHorizontalScrollPosition)
+ needRethrow = true;
+ }
+
+ // See whether we possibly need to re-throw because the final snapped position is
+ // no longer snapped. This can occur when the snapped position was estimated due to virtual
+ // layout, and the actual snapped position (i.e. once the relevent elements have been measured)
+ // turns out to be different.
+ // We also do this when pageScrolling is enabled to make sure we snap to a valid page position
+ // after an orientation change - since an orientation change necessarily moves all the page
+ // boundaries.
+ if (scrollSnappingMode != ScrollSnappingMode.NONE || pageScrollingEnabled)
+ {
+ // NOTE: a lighter-weight way of doing this would be to retain the element
+ // at the end of the throw and see whether its bounds have changed.
+ if (canScrollHorizontally)
+ if (getSnappedPosition(throwFinalHSP, HORIZONTAL_SCROLL_POSITION) != throwFinalHSP)
+ needRethrow = true;
+
+ if (canScrollVertically)
+ if (getSnappedPosition(throwFinalVSP, VERTICAL_SCROLL_POSITION) != throwFinalVSP)
+ needRethrow = true;
+ }
+
+ if (throwEffect && throwEffect.isPlaying && needRethrow)
+ {
+ // There's currently a throw animation playing, and it's throwing to a
+ // now-incorrect position.
+ if (orientationChange)
+ {
+ // The throw end position became invalid because the device
+ // orientation changed. In this case, we just want to stop
+ // the throw animation and snap to valid positions. We don't
+ // want to animate to the final position because this may
+ // require changing directions relative to the current throw,
+ // which looks strange.
+ throwEffect.stop();
+ snapContentScrollPosition();
+ }
+ else
+ {
+ // The size of the content may have changed during the throw.
+ // In this case, we'll stop the current animation and start
+ // a new one that gets us to the correct position.
+
+ // Get the effect's current velocity
+ var velocity:Point = throwEffect.getCurrentVelocity();
+
+ // Stop the existing throw animation now that we've determined its current velocities.
+ stoppedPreemptively = true;
+ throwEffect.stop();
+ stoppedPreemptively = false;
+
+ // Now perform a new throw to get us to the right position.
+ if (setUpThrowEffect(-velocity.x, -velocity.y))
+ throwEffect.play();
+ }
+ }
+ else if (!inTouchInteraction)
+ {
+ // No touch interaction is in effect, but the content may be sitting at
+ // a scroll position that is now invalid. If so, snap the content to
+ // a valid position. The most likely reason we get here is that the
+ // device orientation changed while the content is stationary (i.e. not
+ // in an animated throw)
+
+ // If the orientation changed and orientationChangeSnapElement is set to a
+ // valid value, then we will attempt to snap to the same item/page that
+ // was snapped prior to the orientation change.
+ if (orientationChange && orientationChangeSnapElement != -1)
+ {
+ if (scrollSnappingMode == ScrollSnappingMode.NONE && pageScrollingEnabled)
+ {
+ // Paging without item snapping. We want to snap to the same page, as
+ // long as the number of pages is the same.
+ // The number of pages being different indicates that the relationship
+ // between pages and content is unknown, and it makes no sense to try and
+ // retain the same page.
+ if (previousOrientationPageCount == getCurrentPageCount())
+ {
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+
+ if (canScrollHorizontally)
+ {
+ viewport.horizontalScrollPosition = orientationChangeSnapElement * viewportWidth;
+ currentPageScrollPosition = viewport.horizontalScrollPosition;
+ }
+
+ else if (canScrollVertically)
+ {
+ viewport.verticalScrollPosition = orientationChangeSnapElement * viewportHeight;
+ currentPageScrollPosition = viewport.verticalScrollPosition;
+ }
+ }
+ }
+ else
+ {
+ // Snap directly to the item that was snapped before the orientation changed.
+ // If this results in an invalid scroll position for the new orientation, the
+ // call to snapContentScrollPosition below will fix this.
+ snapElement(orientationChangeSnapElement,false);
+ }
+ orientationChangeSnapElement = -1;
+ }
+ snapContentScrollPosition();
+ }
+ } */
+
+
+ /**
+ * @private
+ */
+ /* private function handleSizeChange():void
+ {
+ // The content size has changed, so the current scroll
+ // position and/or any in-progress throw may need to be adjusted.
+ checkScrollPosition();
+
+ // See whether the current page scroll position still needs to be initialized.
+ if (pageScrollingEnabled && isNaN(currentPageScrollPosition))
+ determineCurrentPageScrollPosition();
+ }*/
+
+ /**
+ * @private
+ * Determines the minimum/maximum allowed scroll positions
+ * when in leading-edge snapping mode
+ */
+ /*private function determineLeadingEdgeSnappingScrollRanges():void
+ {
+ var layout:LayoutBase = viewportLayout;
+ var maxPositionItemIndex:int;
+ var maxPositionItemBounds:Rectangle;
+
+ // Locate the element nearest the leading edge: top for vertical scrolling, left for horizontal.
+ var firstItemIndex:int = layout.getElementNearestScrollPosition(new Point(0, 0), "topLeft");
+ var firstItemBounds:Rectangle = layout.getElementBounds(firstItemIndex);
+ if (canScrollHorizontally)
+ {
+ // The minimum scroll position aligns the first element's leading (left) edge
+ // with the left edge of the viewport.
+ minHorizontalScrollPosition = firstItemBounds.left;
+
+ // The maximum scroll position is one which aligns an element's leading edge
+ // with the leading edge of the viewport, but also leaves the last element
+ // fully visible.
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ maxPositionItemIndex = layout.getElementNearestScrollPosition(new Point(viewport.contentWidth-viewportWidth, 0), "topLeft");
+ do
+ {
+ maxPositionItemBounds = layout.getElementBounds(maxPositionItemIndex);
+ if ((viewport.contentWidth - maxPositionItemBounds.left) <= viewportWidth)
+ break;
+ }
+ while (++maxPositionItemIndex < layout.target.numElements);
+ maxHorizontalScrollPosition = maxPositionItemBounds.left;
+ }
+ else if (canScrollVertically)
+ {
+ // The minimum scroll position aligns the first element's leading (left) edge
+ // with the left edge of the viewport.
+ minVerticalScrollPosition = firstItemBounds.top;
+
+ // The maximum scroll position is one which aligns an element's leading edge
+ // with the leading edge of the viewport, but also leaves the last element
+ // fully visible.
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+ maxPositionItemIndex = layout.getElementNearestScrollPosition(new Point(0, viewport.contentHeight-viewportHeight), "topLeft");
+ do
+ {
+ maxPositionItemBounds = layout.getElementBounds(maxPositionItemIndex);
+ if ((viewport.contentHeight - maxPositionItemBounds.top) <= viewportHeight)
+ break;
+ }
+ while (++maxPositionItemIndex < layout.target.numElements);
+ maxVerticalScrollPosition = maxPositionItemBounds.top;
+ }
+ } */
+
+ /**
+ * @private
+ * Determines the minimum/maximum allowed scroll positions
+ * when in center snapping mode
+ */
+ /* private function determineCenterSnappingScrollRanges():void
+ {
+ var layout:LayoutBase = viewportLayout;
+ var leadingItemIndex:int;
+ var leadingItemBounds:Rectangle;
+ var trailingItemIndex:int;
+ var trailingItemBounds:Rectangle;
+
+ // For center snapping mode, the min/max positions must be set such that
+ // any element in the layout can be scrolled into the center position.
+
+ // Find the element nearest the zero point.
+ leadingItemIndex = layout.getElementNearestScrollPosition(new Point(0, 0), "center");
+ leadingItemBounds = layout.getElementBounds(leadingItemIndex);
+
+ if (canScrollHorizontally)
+ {
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ trailingItemIndex = layout.getElementNearestScrollPosition(new Point(viewport.contentWidth, 0), "center");
+ trailingItemBounds = layout.getElementBounds(trailingItemIndex);
+ minVerticalScrollPosition = maxVerticalScrollPosition = 0;
+
+ // Calculate the scroll position that puts the first element into the center.
+ minHorizontalScrollPosition = leadingItemBounds.left + (leadingItemBounds.width/2) - (viewportWidth/2);
+
+ // Calculate the scroll position that puts the last element into the center.
+ maxHorizontalScrollPosition = trailingItemBounds.left + (trailingItemBounds.width/2) - (viewportWidth/2);
+ }
+ else if (canScrollVertically)
+ {
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+ trailingItemIndex = layout.getElementNearestScrollPosition(new Point(0, viewport.contentHeight), "center");
+ trailingItemBounds = layout.getElementBounds(trailingItemIndex);
+ minHorizontalScrollPosition = maxHorizontalScrollPosition = 0;
+
+ // Calculate the scroll position that puts the first element into the center.
+ minVerticalScrollPosition = leadingItemBounds.top + (leadingItemBounds.height/2) - (viewportHeight/2);
+
+ // Calculate the scroll position that puts the last element into the center.
+ maxVerticalScrollPosition = trailingItemBounds.top + (trailingItemBounds.height/2) - (viewportHeight/2);
+ }
+ } */
+
+ /**
+ * @private
+ * Determines the minimum/maximum allowed scroll positions
+ * when in trailing-edge snapping mode
+ */
+ /* private function determineTrailingEdgeSnappingScrollRanges():void
+ {
+ var layout:LayoutBase = viewportLayout;
+ var snappedItemIndex:int;
+ var snappedItemBounds:Rectangle;
+ var lastItemIndex:int;
+ var lastItemBounds:Rectangle;
+
+ if (canScrollHorizontally)
+ {
+ // The max scroll position is the one which aligns the last element's right edge
+ // with the viewport's right edge
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ lastItemIndex = layout.getElementNearestScrollPosition(new Point(viewport.contentWidth, 0), "bottomRight");
+ lastItemBounds = layout.getElementBounds(lastItemIndex);
+ maxHorizontalScrollPosition = lastItemBounds.right - viewportWidth;
+
+ // The minimum scroll position is the one which aligns an element's right edge with the
+ // right edge of the viewport, but also leaves the first element fully visible.
+ snappedItemIndex = layout.getElementNearestScrollPosition(new Point(viewportWidth, 0), "bottomRight");
+ do
+ {
+ snappedItemBounds = layout.getElementBounds(snappedItemIndex);
+ if (snappedItemBounds.right <= viewportWidth)
+ break;
+ }
+ while (--snappedItemIndex >= 0);
+ minHorizontalScrollPosition = snappedItemBounds.right - viewportWidth;
+ }
+ else if (canScrollVertically)
+ {
+ // The max scroll position is the one which aligns the last element's bottom edge
+ // with the viewport's bottom edge
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+ lastItemIndex = layout.getElementNearestScrollPosition(new Point(0, viewport.contentHeight), "bottomRight");
+ lastItemBounds = layout.getElementBounds(lastItemIndex);
+ maxVerticalScrollPosition = lastItemBounds.bottom - viewportHeight;
+
+ // The minimum scroll position is the one which aligns an element's right edge with the
+ // right edge of the viewport, but also leaves the first element fully visible.
+ snappedItemIndex = layout.getElementNearestScrollPosition(new Point(0, viewportHeight), "bottomRight");
+ do
+ {
+ snappedItemBounds = layout.getElementBounds(snappedItemIndex);
+ if (snappedItemBounds.bottom <= viewportHeight)
+ break;
+ }
+ while (--snappedItemIndex >= 0);
+ minVerticalScrollPosition = snappedItemBounds.bottom - viewportHeight;
+ }
+ } */
+
+ /**
+ * @private
+ * Determines the minimum/maximum allowed scroll positions.
+ */
+ /* private function determineScrollRanges():void
+ {
+ minVerticalScrollPosition = maxVerticalScrollPosition = 0;
+ minHorizontalScrollPosition = maxHorizontalScrollPosition = 0;
+
+ if (viewport)
+ {
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+
+ // For now, having both bounce and pull disabled puts us into a sort of
+ // "endless" scrolling mode, in which there are practically no minimum/maximum
+ // edges to bounce/pull against.
+ // TODO (eday): bounce and pull probably don't need to be controlled separately. These
+ // should be combined into a single property.
+ if (!bounceEnabled && !pullEnabled)
+ {
+ minVerticalScrollPosition = minHorizontalScrollPosition = -Number.MAX_VALUE;
+ maxVerticalScrollPosition = maxHorizontalScrollPosition = Number.MAX_VALUE;
+ }
+ else if (scrollSnappingMode == ScrollSnappingMode.NONE)
+ {
+ var remaining:Number;
+ maxVerticalScrollPosition = viewport.contentHeight > viewportHeight ?
+ viewport.contentHeight-viewportHeight : 0;
+ if (pageScrollingEnabled && canScrollVertically && viewportHeight != 0)
+ {
+ // If the content height isn't an exact multiple of the viewport height,
+ // then we make sure the max scroll position allows for a full page (including
+ // padding) at the end.
+ remaining = viewport.contentHeight % viewportHeight;
+ if (remaining)
+ maxVerticalScrollPosition += viewportHeight - remaining;
+ }
+
+ maxHorizontalScrollPosition = viewport.contentWidth > viewportWidth ?
+ viewport.contentWidth-viewportWidth : 0;
+ if (pageScrollingEnabled && canScrollHorizontally && viewportWidth != 0)
+ {
+ // If the content width isn't an exact multiple of the viewport width,
+ // then we make sure the max scroll position allows for a full page (including
+ // padding) at the end.
+ remaining = viewport.contentWidth % viewportWidth;
+ if (remaining)
+ maxHorizontalScrollPosition += viewportWidth - remaining;
+ }
+ }
+ else
+ {
+ var layout:LayoutBase = viewportLayout;
+
+ // Nothing to do if there is no layout or no layout elements
+ if (!layout || layout.target.numElements == 0)
+ return;
+
+ // Nothing to do if the viewport dimensions have not been set yet
+ if ((canScrollHorizontally && viewportWidth == 0) || (canScrollVertically && viewportHeight == 0))
+ return;
+
+ switch (scrollSnappingMode)
+ {
+ case ScrollSnappingMode.LEADING_EDGE:
+ determineLeadingEdgeSnappingScrollRanges();
+ break;
+ case ScrollSnappingMode.CENTER:
+ determineCenterSnappingScrollRanges();
+ break;
+ case ScrollSnappingMode.TRAILING_EDGE:
+ determineTrailingEdgeSnappingScrollRanges();
+ break;
+ }
+ }
+ }
+ if (verticalScrollBar)
+ {
+ verticalScrollBar.contentMinimum = minVerticalScrollPosition;
+ verticalScrollBar.contentMaximum = maxVerticalScrollPosition;
+ }
+ if (horizontalScrollBar)
+ {
+ horizontalScrollBar.contentMinimum = minHorizontalScrollPosition;
+ horizontalScrollBar.contentMaximum = maxHorizontalScrollPosition;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* private function determineCurrentPageScrollPosition():void
+ {
+ if (canScrollHorizontally)
+ {
+ viewport.horizontalScrollPosition = getSnappedPosition(viewport.horizontalScrollPosition,HORIZONTAL_SCROLL_POSITION);
+ currentPageScrollPosition = viewport.horizontalScrollPosition;
+ }
+ else if (canScrollVertically)
+ {
+ viewport.verticalScrollPosition = getSnappedPosition(viewport.verticalScrollPosition,VERTICAL_SCROLL_POSITION);
+ currentPageScrollPosition = viewport.verticalScrollPosition;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* private function handleSizeChangeOnUpdateComplete(event:FlexEvent):void
+ {
+ viewport.removeEventListener(FlexEvent.UPDATE_COMPLETE,
+ handleSizeChangeOnUpdateComplete);
+
+ handleSizeChange();
+ } */
+
+ /**
+ * @private
+ */
+ /* private function viewport_resizeHandler(event:Event):void
+ {
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ // If the viewport dimensions have changed, then we may need to update the
+ // scroll ranges and snap the scroll position per the new viewport size.
+ viewport.addEventListener(FlexEvent.UPDATE_COMPLETE,
+ handleSizeChangeOnUpdateComplete);
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* private function viewport_propertyChangeHandler(event:PropertyChangeEvent):void
+ {
+ switch(event.property)
+ {
+ case "contentWidth":
+ case "contentHeight":
+ invalidateSkin();
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ // If the content size changed, then the valid scroll position ranges
+ // may have changed. In this case, we need to schedule an updateComplete
+ // handler to check and potentially correct the scroll positions.
+ viewport.addEventListener(FlexEvent.UPDATE_COMPLETE,
+ handleSizeChangeOnUpdateComplete);
+ }
+ break;
+
+ case VERTICAL_SCROLL_POSITION:
+ case HORIZONTAL_SCROLL_POSITION:
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ // Determine whether the scroll position is being modified programmatically (i.e.
+ // not due to a touch interaction or animation)
+ if (!inTouchInteraction && (!snapElementAnimation || !snapElementAnimation.isPlaying))
+ {
+ // We need to ensure the scroll position is always an appropriately snapped value.
+ if (!settingScrollPosition)
+ {
+ settingScrollPosition = true;
+ viewport[event.property] = getSnappedPosition(Number(event.newValue), String(event.property));
+ settingScrollPosition = false;
+ }
+
+ // Reset the page scroll position from the programmatically-changed scroll position.
+ if (canScrollHorizontally && event.property == HORIZONTAL_SCROLL_POSITION)
+ currentPageScrollPosition = viewport.horizontalScrollPosition;
+ if (canScrollVertically && event.property == VERTICAL_SCROLL_POSITION)
+ currentPageScrollPosition = viewport.verticalScrollPosition;
+ }
+ else if (throwEffect && throwEffect.isPlaying && throwEffect.isSnapping)
+ {
+ // If a throw animation is playing just to snap an element into position,
+ // then we want to stop the animation as soon as the final position is reached
+ // to avoid very short snaps taking a relatively long time to complete.
+ if (Math.abs(viewport.horizontalScrollPosition - throwEffect.finalPosition.x) < 1 &&
+ Math.abs(viewport.verticalScrollPosition - throwEffect.finalPosition.y) < 1)
+ {
+ throwEffect.stop();
+ snapContentScrollPosition();
+ }
+ }
+ }
+ break;
+ }
+ } */
+
+ // This keeps us from infinitely recursing while changing a scroll position from
+ // within the scroll position change handler.
+ //private var settingScrollPosition:Boolean = false;
+
+ /**
+ * @private
+ * Listens for any focusIn events from descendants
+ */
+ /* override protected function focusInHandler(event:FocusEvent):void
+ {
+ super.focusInHandler(event);
+
+ var fm:IFocusManager = focusManager;
+
+ // When we gain focus, make sure the focused element is visible
+ if (fm && viewport && ensureElementIsVisibleForSoftKeyboard)
+ {
+ var elt:IVisualElement = fm.getFocus() as IVisualElement;
+ lastFocusedElement = elt;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* override protected function focusOutHandler(event:FocusEvent):void
+ {
+ super.focusOutHandler(event);
+ lastFocusedElement = null;
+ } */
+
+ /**
+ * @private
+ */
+ /* private function orientationChangingHandler(event:Event):void
+ {
+ orientationChangeSnapElement = -1;
+
+ // The orientation is about to change, so we see which item/page is currently snapped
+ // and remember it so we can snap to it again when the orientation change is complete.
+ if (scrollSnappingMode == ScrollSnappingMode.NONE && pageScrollingEnabled)
+ {
+ // For paging without item snapping, we remember the number of the current page.
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+
+ if (canScrollHorizontally && viewportWidth != 0)
+ orientationChangeSnapElement = currentPageScrollPosition / viewportWidth;
+ else if (canScrollVertically && viewportHeight != 0)
+ orientationChangeSnapElement = currentPageScrollPosition / viewportHeight;
+
+ // Remember the page count so we'll know whether it changed.
+ previousOrientationPageCount = getCurrentPageCount();
+ }
+ else if (scrollSnappingMode != ScrollSnappingMode.NONE)
+ {
+ // For item snapping, we remember which specific element is currently snapped.
+
+ if (canScrollHorizontally)
+ getSnappedPosition(viewport.horizontalScrollPosition, HORIZONTAL_SCROLL_POSITION);
+ else if (canScrollVertically)
+ getSnappedPosition(viewport.verticalScrollPosition, VERTICAL_SCROLL_POSITION);
+
+ // lastSnappedElement was set as a side-effect of the call to getSnappedPosition above.
+ orientationChangeSnapElement = lastSnappedElement;
+ }
+
+ // Force the viewport layout to clear its cache of element
+ // dimensions so it can be repopulated with correct values
+ // after the orientation change is complete.
+ if (viewportLayout)
+ viewportLayout.clearVirtualLayoutCache();
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: IVisualElementContainer
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns 1 if there is a viewport, 0 otherwise.
+ *
+ * @return The number of visual elements in this visual container
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function get numElements():int
+ {
+ return viewport ? 1 : 0;
+ } */
+
+ /**
+ * Returns the viewport if there is a viewport and the
+ * index passed in is 0. Otherwise, it throws a RangeError.
+ *
+ * @param index The index of the element to retrieve.
+ *
+ * @return The element at the specified index.
+ *
+ * @throws RangeError If the index position does not exist in the child list.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function getElementAt(index:int):IVisualElement
+ {
+ if (viewport && index == 0)
+ return viewport;
+ else
+ throw new RangeError(resourceManager.getString("components", "indexOutOfRange", [index]));
+ } */
+
+ /**
+ * Returns 0 if the element passed in is the viewport.
+ * Otherwise, it throws an ArgumentError.
+ *
+ * @param element The element to identify.
+ *
+ * @return The index position of the element to identify.
+ *
+ * @throws ArgumentError If the element is not a child of this object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function getElementIndex(element:IVisualElement):int
+ {
+ if (element != null && element == viewport)
+ return 0;
+ else
+ throw ArgumentError(resourceManager.getString("components", "elementNotFoundInScroller", [element]));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child.
+ * Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function addElement(element:IVisualElement):IVisualElement
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function addElementAt(element:IVisualElement, index:int):IVisualElement
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function removeElement(element:IVisualElement):IVisualElement
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function removeElementAt(index:int):IVisualElement
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function removeAllElements():void
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function setElementIndex(element:IVisualElement, index:int):void
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function swapElements(element1:IVisualElement, element2:IVisualElement):void
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ /**
+ *
+ * This operation is not supported in Scroller.
+ * A Scroller control has only one child. Use the <code>viewport</code> property to manipulate
+ * it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Royale 0.9.4
+ */
+ /* public function swapElementsAt(index1:int, index2:int):void
+ {
+ throw new ArgumentError(resourceManager.getString("components", "operationNotSupported"));
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Private Helper Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Helper method to easily invalidate the skins's size and display list.
+ */
+ /* private function invalidateSkin():void
+ {
+ if (skin)
+ {
+ skin.invalidateSize()
+ skin.invalidateDisplayList();
+ }
+ } */
+
+ /**
+ * @private
+ * Helper method to grab the ScrollerLayout.
+ */
+ /* mx_internal function get scrollerLayout():ScrollerLayout
+ {
+ if (skin)
+ return Group(skin).layout as ScrollerLayout;
+
+ return null;
+ } */
+
+ /**
+ * @private
+ * Helper method to grab scrollerLayout.canScrollHorizontally
+ */
+ /* private function get canScrollHorizontally():Boolean
+ {
+ var layout:ScrollerLayout = scrollerLayout;
+ if (layout)
+ return layout.canScrollHorizontally;
+
+ return false;
+ } */
+
+ /**
+ * @private
+ * Helper method to grab scrollerLayout.canScrollVertically
+ */
+ /* private function get canScrollVertically():Boolean
+ {
+ var layout:ScrollerLayout = scrollerLayout;
+ if (layout)
+ return layout.canScrollVertically;
+
+ return false;
+ } */
+
+ /**
+ * @private
+ * Helper method to grab viewport.layout
+ */
+ /* private function get viewportLayout():LayoutBase
+ {
+ if (viewport is GroupBase)
+ return GroupBase(viewport).layout;
+ else if (viewport is SkinnableContainer)
+ return SkinnableContainer(viewport).layout;
+ return null;
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Touch scrolling methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Add touch listeners
+ */
+ /* private function installTouchListeners():void
+ {
+ addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
+ addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_STARTING, touchInteractionStartingHandler);
+ addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START, touchInteractionStartHandler);
+ addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_END, touchInteractionEndHandler);
+
+ // capture mouse listeners to help block click and mousedown events.
+ // mousedown is blocked when a scroll is in progress
+ // click is blocked when a scroll is in progress (or just finished)
+ addEventListener(MouseEvent.CLICK, touchScrolling_captureMouseHandler, true);
+ addEventListener(MouseEvent.MOUSE_DOWN, touchScrolling_captureMouseHandler, true);
+ } */
+
+ /**
+ * @private
+ */
+ /* private function uninstallTouchListeners():void
+ {
+ removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
+ removeEventListener(TouchInteractionEvent.TOUCH_INTERACTION_STARTING, touchInteractionStartingHandler);
+ removeEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START, touchInteractionStartHandler);
+ removeEventListener(TouchInteractionEvent.TOUCH_INTERACTION_END, touchInteractionEndHandler);
+
+ removeEventListener(MouseEvent.CLICK, touchScrolling_captureMouseHandler, true);
+ removeEventListener(MouseEvent.MOUSE_DOWN, touchScrolling_captureMouseHandler, true);
+ } */
+
+ /**
+ * @private
+ * This function determines whether a switch to an adjacent page is warranted, given
+ * the distance dragged and/or the velocity thrown.
+ */
+ /* private function determineNewPageScrollPosition(velocityX:Number, velocityY:Number):void
+ {
+ // Convert the paging velocity threshold from inches/second to pixels/millisecond
+ var minVelocityPixels:Number = pageThrowVelocityThreshold * Capabilities.screenDPI / 1000;
+
+ if (canScrollHorizontally)
+ {
+ // Check both the throw velocity and the drag distance. If either exceeds our threholds, then we switch to the next page.
+ if (velocityX < -minVelocityPixels || viewport.horizontalScrollPosition >= currentPageScrollPosition + viewport.width * pageDragDistanceThreshold)
+ {
+ // Go to the next horizontal page
+ // Set the new page scroll position so the throw effect animates the page into place
+ currentPageScrollPosition = Math.min(currentPageScrollPosition + viewport.width, maxHorizontalScrollPosition);
+ }
+ else if (velocityX > minVelocityPixels || viewport.horizontalScrollPosition <= currentPageScrollPosition - viewport.width * pageDragDistanceThreshold)
+ {
+ // Go to the previous horizontal page
+ currentPageScrollPosition = Math.max(currentPageScrollPosition - viewport.width, minHorizontalScrollPosition);
+ }
+
+ // Ensure the new page position is snapped appropriately
+ currentPageScrollPosition = getSnappedPosition(currentPageScrollPosition, HORIZONTAL_SCROLL_POSITION);
+ }
+ else if (canScrollVertically)
+ {
+ // Check both the throw velocity and the drag distance. If either exceeds our threholds, then we switch to the next page.
+ if (velocityY < -minVelocityPixels || viewport.verticalScrollPosition >= currentPageScrollPosition + viewport.height * pageDragDistanceThreshold)
+ {
+ // Go to the next vertical page
+ // Set the new page scroll position so the throw effect animates the page into place
+ currentPageScrollPosition = Math.min(currentPageScrollPosition + viewport.height, maxVerticalScrollPosition);
+ }
+ else if (velocityY > minVelocityPixels || viewport.verticalScrollPosition <= currentPageScrollPosition - viewport.height * pageDragDistanceThreshold)
+ {
+ // Go to the previous vertical page
+ currentPageScrollPosition = Math.max(currentPageScrollPosition - viewport.height, minVerticalScrollPosition);
+ }
+
+ // Ensure the new page position is snapped appropriately
+ currentPageScrollPosition = getSnappedPosition(currentPageScrollPosition, VERTICAL_SCROLL_POSITION);
+ }
+ } */
+
+ /**
+ * @private
+ * Set up the effect to be used for the throw animation
+ */
+ /* private function setUpThrowEffect(velocityX:Number, velocityY:Number):Boolean
+ {
+ if (!throwEffect)
+ {
+ throwEffect = new ThrowEffect();
+ throwEffect.target = viewport;
+ throwEffect.addEventListener(EffectEvent.EFFECT_END, throwEffect_effectEndHandler);
+ }
+
+ var minHSP:Number = minHorizontalScrollPosition;
+ var minVSP:Number = minVerticalScrollPosition;
+ var maxHSP:Number = maxHorizontalScrollPosition;
+ var maxVSP:Number = maxVerticalScrollPosition;
+
+ if (pageScrollingEnabled)
+ {
+ // See whether a page switch is warranted for this touch gesture.
+ determineNewPageScrollPosition(velocityX, velocityY);
+
+ // The throw velocity is greatly attenuated in paging mode.
+ // Note that this must be done after the call above to
+ // determineNewPageScrollPosition which compares the velocity
+ // to our threshold.
+ const PAGING_VELOCITY_FACTOR:Number = 0.25;
+ velocityX *= PAGING_VELOCITY_FACTOR;
+ velocityY *= PAGING_VELOCITY_FACTOR;
+
+ // Make the scroller "lock" to the current page
+ if (canScrollHorizontally)
+ minHSP = maxHSP = currentPageScrollPosition;
+ else if (canScrollVertically)
+ minVSP = maxVSP = currentPageScrollPosition;
+ }
+
+ throwEffect.propertyNameX = canScrollHorizontally ? HORIZONTAL_SCROLL_POSITION : null;
+ throwEffect.propertyNameY = canScrollVertically ? VERTICAL_SCROLL_POSITION : null;
+ throwEffect.startingVelocityX = velocityX;
+ throwEffect.startingVelocityY = velocityY;
+ throwEffect.startingPositionX = viewport.horizontalScrollPosition;
+ throwEffect.startingPositionY = viewport.verticalScrollPosition;
+ throwEffect.minPositionX = minHSP;
+ throwEffect.minPositionY = minVSP;
+ throwEffect.maxPositionX = maxHSP;
+ throwEffect.maxPositionY = maxVSP;
+ throwEffect.decelerationFactor = throwEffectDecelFactor;
+
+ // In snapping mode, we need to ensure that the final throw position is snapped appropriately.
+ throwEffect.finalPositionFilterFunction = scrollSnappingMode == ScrollSnappingMode.NONE ? null : getSnappedPosition;
+
+ throwReachedMaximumScrollPosition = false;
+ if (throwEffect.setup())
+ {
+ throwFinalHSP = throwEffect.finalPosition.x;
+ if (canScrollHorizontally && bounceEnabled && throwFinalHSP == maxHorizontalScrollPosition)
+ throwReachedMaximumScrollPosition = true;
+ throwFinalVSP = throwEffect.finalPosition.y;
+ if (canScrollVertically && bounceEnabled && throwFinalVSP == maxVerticalScrollPosition)
+ throwReachedMaximumScrollPosition = true;
+ }
+ else
+ {
+ touchScrollHelper.endTouchScroll();
+ return false;
+ }
+ return true;
+ } */
+
+
+ /**
+ * @private
+ * This function takes a scroll position and the associated property name, and finds
+ * the nearest snapped position (i.e. one that satifises the current scrollSnappingMode).
+ */
+ /* private function getSnappedPosition(position:Number, propertyName:String):Number
+ {
+ var layout:LayoutBase = viewportLayout;
+ var nearestElementIndex:int = -1;
+ var nearestElementBounds:Rectangle;
+
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+
+ if (scrollSnappingMode == ScrollSnappingMode.NONE && pageScrollingEnabled)
+ {
+ // If we're in paging mode and no snapping is enabled, then we must snap
+ // the position to the beginning of a page. i.e. a multiple of the
+ // viewport size.
+ var offset:Number;
+ if (canScrollHorizontally && propertyName == HORIZONTAL_SCROLL_POSITION &&
+ viewportWidth != 0 && viewport.contentWidth != 0)
+ {
+ // Get the offset into the current page. If less than half way, snap
+ // to the beginning of the page. Otherwise, snap to the beginning
+ // of the next page
+ offset = position % viewportWidth;
+ if (offset < viewportWidth / 2)
+ position -= offset;
+ else
+ position += viewportWidth - offset;
+
+ // Clip the position to the valid min/max range
+ position = Math.min(Math.max(minHorizontalScrollPosition, position), maxHorizontalScrollPosition);
+ }
+ else if (canScrollVertically && propertyName == VERTICAL_SCROLL_POSITION &&
+ viewportHeight != 0 && viewport.contentHeight != 0)
+ {
+ offset = position % viewportHeight;
+ if (offset < viewportHeight / 2)
+ position -= offset;
+ else
+ position += viewportHeight - offset;
+
+ // Clip the position to the valid min/max range
+ position = Math.min(Math.max(minVerticalScrollPosition, position), maxVerticalScrollPosition);
+ }
+ }
+
+ if (layout && layout.target.numElements > 0)
+ {
+ switch (_scrollSnappingMode)
+ {
+ case ScrollSnappingMode.LEADING_EDGE:
+ if (canScrollHorizontally && propertyName == HORIZONTAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(position, 0), "topLeft");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.left;
+ }
+ else if (canScrollVertically && propertyName == VERTICAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(0, position), "topLeft");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.top;
+ }
+ break;
+ case ScrollSnappingMode.CENTER:
+ if (canScrollHorizontally && propertyName == HORIZONTAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(position + viewportWidth/2, 0), "center");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.left + (nearestElementBounds.width / 2) - (viewportWidth / 2);
+ }
+ else if (canScrollVertically && propertyName == VERTICAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(0, position + viewportHeight/2), "center");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.top + (nearestElementBounds.height / 2) - (viewportHeight / 2);
+ }
+ break;
+ case ScrollSnappingMode.TRAILING_EDGE:
+ if (canScrollHorizontally && propertyName == HORIZONTAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(position + viewportWidth, 0), "bottomRight");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.right - viewportWidth;
+ }
+ else if (canScrollVertically && propertyName == VERTICAL_SCROLL_POSITION)
+ {
+ nearestElementIndex = layout.getElementNearestScrollPosition(new Point(0, position + viewportHeight), "bottomRight");
+ nearestElementBounds = layout.getElementBounds(nearestElementIndex);
+ position = nearestElementBounds.bottom - viewportHeight;
+ }
+ break;
+ }
+ }
+ lastSnappedElement = nearestElementIndex;
+ return Math.round(position);
+ } */
+
+ /**
+ * @private
+ * When the throw or drag scroll is over, we should play a nice
+ * animation to hide the scrollbars.
+ */
+ /* private function hideScrollBars():void
+ {
+ if (!hideScrollBarAnimation)
+ {
+ hideScrollBarAnimation = new Animate();
+ hideScrollBarAnimation.addEventListener(EffectEvent.EFFECT_END, hideScrollBarAnimation_effectEndHandler);
+ hideScrollBarAnimation.duration = 500;
+ var alphaMP:Vector.<MotionPath> = Vector.<MotionPath>([new SimpleMotionPath("alpha", 1, 0)]);
+ hideScrollBarAnimation.motionPaths = alphaMP;
+ }
+
+ // set up the target scrollbars (hsb and/or vsb)
+ var targets:Array = [];
+ if (horizontalScrollBar && horizontalScrollBar.visible)
+ {
+ targets.push(horizontalScrollBar);
+ }
+
+ if (verticalScrollBar && verticalScrollBar.visible)
+ {
+ targets.push(verticalScrollBar);
+ }
+
+ // we keep track of hideScrollBarAnimationPrematurelyStopped so that we know
+ // if the effect ended naturally or if we prematurely called stop()
+ hideScrollBarAnimationPrematurelyStopped = false;
+
+ hideScrollBarAnimation.play(targets);
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ /*override protected function createChildren():void
+ {
+ super.createChildren();
+
+ // Only listen for softKeyboardEvents if the
+ // softKeyboardBehavior attribute in the application descriptor equals "none"
+ if (Application.softKeyboardBehavior == "none")
+ {
+ addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE,
+ softKeyboardActivateHandler, false,
+ EventPriority.DEFAULT, true);
+ addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE,
+ softKeyboardActivateCaptureHandler, true,
+ EventPriority.DEFAULT, true);
+ addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE,
+ softKeyboardDeactivateHandler, false,
+ EventPriority.DEFAULT, true);
+ addEventListener(CaretBoundsChangeEvent.CARET_BOUNDS_CHANGE,
+ caretBoundsChangeHandler);
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* override public function styleChanged(styleProp:String):void
+ {
+ super.styleChanged(styleProp);
+
+ var allStyles:Boolean = (styleProp == null || styleProp == "styleName");
+
+ if (allStyles || styleProp == "horizontalScrollPolicy" ||
+ styleProp == "verticalScrollPolicy")
+ {
+ invalidateSkin();
+ }
+
+ if (allStyles || styleProp == "interactionMode")
+ {
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ installTouchListeners();
+
+ // Need to make sure the scroll ranges are updated now, since they may
+ // not have been if the scroller was in non-touch mode when the content
+ // was created/changed.
+ scrollRangesChanged = true;
+ invalidateProperties();
+
+ if (!touchScrollHelper)
+ {
+ touchScrollHelper = new TouchScrollHelper();
+ touchScrollHelper.target = this;
+
+ // Install callbacks with the helper
+ // The dragFunction is called repeatedly during dragging/scrolling.
+ touchScrollHelper.dragFunction = performDrag;
+
+ // The throwFunction is called once when dragging is done and the finger is released.
+ touchScrollHelper.throwFunction = performThrow;
+ }
+
+ // We don't support directly interacting with the scrollbars in touch mode
+ if (horizontalScrollBar)
+ {
+ horizontalScrollBar.mouseEnabled = false;
+ horizontalScrollBar.mouseChildren = false;
+ }
+ if (verticalScrollBar)
+ {
+ verticalScrollBar.mouseEnabled = false;
+ verticalScrollBar.mouseChildren = false;
+ }
+ }
+ else
+ {
+ // In case we're not in touch mode, we need to instantiate our deferred skin parts immediately
+ // TODO (egeorgie): support deferred scrollbar parts in non-touch mode
+ ensureDeferredHScrollBarCreated();
+ ensureDeferredVScrollBarCreated();
+
+ uninstallTouchListeners();
+
+ if (horizontalScrollBar)
+ {
+ horizontalScrollBar.mouseEnabled = true;
+ horizontalScrollBar.mouseChildren = true;
+ }
+ if (verticalScrollBar)
+ {
+ verticalScrollBar.mouseEnabled = true;
+ verticalScrollBar.mouseChildren = true;
+ }
+ }
+ }
+
+ // If the liveScrolling style was set, set the scrollbars' liveDragging styles
+
+ if (allStyles || styleProp == "liveScrolling")
+ {
+ const liveScrolling:* = getStyle("liveScrolling");
+ if ((liveScrolling === true) || (liveScrolling === false))
+ {
+ if (verticalScrollBar)
+ verticalScrollBar.setStyle("liveDragging", Boolean(liveScrolling));
+ if (horizontalScrollBar)
+ horizontalScrollBar.setStyle("liveDragging", Boolean(liveScrolling));
+ }
+ }
+ }
+ */
+ /**
+ * @private
+ */
+ /* override protected function attachSkin():void
+ {
+ super.attachSkin();
+
+ if (getStyle("interactionMode") != InteractionMode.TOUCH)
+ {
+ // TODO (egeorgie): support deferred scrollbar parts in non-touch mode
+ // In case we're not in touch mode, we need to instantiate our deferred skin parts immediately
+ ensureDeferredHScrollBarCreated();
+ ensureDeferredVScrollBarCreated();
+ }
+
+ Group(skin).layout = new ScrollerLayout();
+ installViewport();
+ skin.addEventListener(MouseEvent.MOUSE_WHEEL, skin_mouseWheelHandler);
+ } */
+
+ /**
+ * @private
+ */
+ /* override protected function detachSkin():void
+ {
+ uninstallViewport();
+ Group(skin).layout = null;
+ skin.removeEventListener(MouseEvent.MOUSE_WHEEL, skin_mouseWheelHandler);
+ super.detachSkin();
+ } */
+
+ /**
+ * @private
+ */
+ /* override protected function partAdded(partName:String, instance:Object):void
+ {
+ super.partAdded(partName, instance);
+
+ const liveScrolling:* = getStyle("liveScrolling");
+ const liveScrollingSet:Boolean = (liveScrolling === true) || (liveScrolling === false);
+ const inTouchMode:Boolean = (getStyle("interactionMode") == InteractionMode.TOUCH);
+
+ if (instance == verticalScrollBar)
+ {
+ verticalScrollBar.viewport = viewport;
+ if (liveScrollingSet)
+ verticalScrollBar.setStyle("liveDragging", Boolean(liveScrolling));
+ verticalScrollBar.contentMinimum = minVerticalScrollPosition;
+ verticalScrollBar.contentMaximum = maxVerticalScrollPosition;
+
+ // We don't support directly interacting with the scrollbars in touch mode
+ if (inTouchMode)
+ {
+ verticalScrollBar.mouseEnabled = false;
+ verticalScrollBar.mouseChildren = false;
+ }
+
+ }
+ else if (instance == horizontalScrollBar)
+ {
+ horizontalScrollBar.viewport = viewport;
+ if (liveScrollingSet)
+ horizontalScrollBar.setStyle("liveDragging", Boolean(liveScrolling));
+ horizontalScrollBar.contentMinimum = minHorizontalScrollPosition;
+ horizontalScrollBar.contentMaximum = maxHorizontalScrollPosition;
+
+ // We don't support directly interacting with the scrollbars in touch mode
+ if (inTouchMode)
+ {
+ horizontalScrollBar.mouseEnabled = false;
+ horizontalScrollBar.mouseChildren = false;
+ }
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* override protected function partRemoved(partName:String, instance:Object):void
+ {
+ super.partRemoved(partName, instance);
+
+ if (instance == verticalScrollBar)
+ verticalScrollBar.viewport = null;
+ else if (instance == horizontalScrollBar)
+ horizontalScrollBar.viewport = null;
+ } */
+
+ /**
+ * @private
+ */
+ /* override protected function commitProperties():void
+ {
+ super.commitProperties();
+
+ if (scrollRangesChanged)
+ {
+ determineScrollRanges();
+ scrollRangesChanged = false;
+ }
+
+ if (pageScrollingChanged)
+ {
+ stopAnimations();
+ determineCurrentPageScrollPosition();
+ pageScrollingChanged = false;
+ }
+
+ if (snappingModeChanged)
+ {
+ stopAnimations();
+ snapContentScrollPosition();
+ snappingModeChanged = false;
+ }
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ /* override protected function keyDownHandler(event:KeyboardEvent):void
+ {
+ super.keyDownHandler(event);
+
+ var vp:IViewport = viewport;
+ if (!vp || event.isDefaultPrevented())
+ return;
+
+ // If a TextField has the focus, then assume it will handle all keyboard
+ // events, and that it will not use Event.preventDefault().
+ if (getFocus() is TextField)
+ return;
+
+ if (verticalScrollBar && verticalScrollBar.visible)
+ {
+ var vspDelta:Number = NaN;
+ switch (event.keyCode)
+ {
+ case Keyboard.UP:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.UP);
+ break;
+ case Keyboard.DOWN:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.DOWN);
+ break;
+ case Keyboard.PAGE_UP:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.PAGE_UP);
+ break;
+ case Keyboard.PAGE_DOWN:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.PAGE_DOWN);
+ break;
+ case Keyboard.HOME:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.HOME);
+ break;
+ case Keyboard.END:
+ vspDelta = vp.getVerticalScrollPositionDelta(NavigationUnit.END);
+ break;
+ }
+ if (!isNaN(vspDelta))
+ {
+ vp.verticalScrollPosition += vspDelta;
+ event.preventDefault();
+ }
+ }
+
+ if (horizontalScrollBar && horizontalScrollBar.visible)
+ {
+ var hspDelta:Number = NaN;
+ switch (event.keyCode)
+ {
+ case Keyboard.LEFT:
+ hspDelta = (layoutDirection == LayoutDirection.LTR) ?
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.LEFT) :
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.RIGHT);
+ break;
+ case Keyboard.RIGHT:
+ hspDelta = (layoutDirection == LayoutDirection.LTR) ?
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.RIGHT) :
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.LEFT);
+ break;
+ case Keyboard.HOME:
+ hspDelta = vp.getHorizontalScrollPositionDelta(NavigationUnit.HOME);
+ break;
+ case Keyboard.END:
+ hspDelta = vp.getHorizontalScrollPositionDelta(NavigationUnit.END);
+ break;
+ // If there's no vertical scrollbar, then map page up/down to
+ // page left,right
+ case Keyboard.PAGE_UP:
+ if (!verticalScrollBar || !(verticalScrollBar.visible))
+ {
+ hspDelta = (LayoutDirection.LTR) ?
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.LEFT) :
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.RIGHT);
+ }
+ break;
+ case Keyboard.PAGE_DOWN:
+ if (!verticalScrollBar || !(verticalScrollBar.visible))
+ {
+ hspDelta = (LayoutDirection.LTR) ?
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.RIGHT) :
+ vp.getHorizontalScrollPositionDelta(NavigationUnit.LEFT);
+ }
+ break;
+ }
+ if (!isNaN(hspDelta))
+ {
+ vp.horizontalScrollPosition += hspDelta;
+ event.preventDefault();
+ }
+ }
+ } */
+
+ /* private function skin_mouseWheelHandler(event:MouseEvent):void
+ {
+ const vp:IViewport = viewport;
+ if (event.isDefaultPrevented() || !vp || !vp.visible)
+ return;
+
+ // Dispatch the "mouseWheelChanging" event. If preventDefault() is called
+ // on this event, the event will be cancelled. Otherwise if the delta
+ // is modified the new value will be used.
+ var changingEvent:FlexMouseEvent = MouseEventUtil.createMouseWheelChangingEvent(event);
+ if (!dispatchEvent(changingEvent))
+ {
+ event.preventDefault();
+ return;
+ }
+
+ const delta:int = changingEvent.delta;
+
+ var nSteps:uint = Math.abs(event.delta);
+ var navigationUnit:uint;
+
+ // Scroll delta "steps". If the VSB is up, scroll vertically,
+ // if -only- the HSB is up then scroll horizontally.
+
+ // TODO: The problem is that viewport.validateNow() doesn’t necessarily
+ // finish the job, see http://bugs.adobe.com/jira/browse/SDK-25740.
+ // Since some imprecision in mouse-wheel scrolling is tolerable this is
+ // ok for now. For 4.next we should add Scroller API for (reliably)
+ // scrolling in different increments and refactor code like this to
+ // depend on it. Also applies to VScroller and HScroller mouse
+ // handlers.
+
+ if (verticalScrollBar && verticalScrollBar.visible)
+ {
+ navigationUnit = (delta < 0) ? NavigationUnit.DOWN : NavigationUnit.UP;
+ for (var vStep:int = 0; vStep < nSteps; vStep++)
+ {
+ var vspDelta:Number = vp.getVerticalScrollPositionDelta(navigationUnit);
+ if (!isNaN(vspDelta))
+ {
+ vp.verticalScrollPosition += vspDelta;
+ if (vp is IInvalidating)
+ IInvalidating(vp).validateNow();
+ }
+ }
+ event.preventDefault();
+ }
+ else if (horizontalScrollBar && horizontalScrollBar.visible)
+ {
+ navigationUnit = (delta < 0) ? NavigationUnit.RIGHT : NavigationUnit.LEFT;
+ for (var hStep:int = 0; hStep < nSteps; hStep++)
+ {
+ var hspDelta:Number = vp.getHorizontalScrollPositionDelta(navigationUnit);
+ if (!isNaN(hspDelta))
+ {
+ vp.horizontalScrollPosition += hspDelta;
+ if (vp is IInvalidating)
+ IInvalidating(vp).validateNow();
+ }
+ }
+ event.preventDefault();
+ }
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers: Touch Scrolling
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Event handler dispatched when someone is about to start scrolling.
+ */
+ /* private function touchInteractionStartingHandler(event:TouchInteractionEvent):void
+ {
+ // if it's us, don't do anything
+ // if it's someone else and we've started scrolling, cancel this event
+ // if it's someone else and we haven't started scrolling, don't do anything
+ // here yet. Worry about it in the touchInteractionStartHandler().
+ if (event.relatedObject != this && inTouchInteraction)
+ {
+ event.preventDefault();
+ }
+ } */
+
+ /**
+ * @private
+ * Event handler dispatched when someone has started scrolling.
+ */
+ /* private function touchInteractionStartHandler(event:TouchInteractionEvent):void
+ {
+ if (event.relatedObject != this)
+ {
+ // if it's not us scrolling, abort our scrolling attempt
+ touchScrollHelper.stopScrollWatch();
+ }
+ else
+ {
+ // we are scrolling
+ captureNextClick = true;
+ captureNextMouseDown = true;
+ preventThrows = false;
+
+ hspBeforeTouchScroll = viewport.horizontalScrollPosition;
+ vspBeforeTouchScroll = viewport.verticalScrollPosition;
+
+ // TODO (rfrishbe): should the ScrollerLayout just listen to
+ // Scroller events to determine this rather than doing it here.
+ // Also should figure out who's in charge of fading the alpha of the
+ // scrollbars...Scroller or ScrollerLayout (or even HScrollbar/VScrollbar)?
+ if (canScrollHorizontally)
+ horizontalScrollInProgress = true;
+
+ if (canScrollVertically)
+ verticalScrollInProgress = true;
+
+ // need to invaliadte the ScrollerLayout object so it'll update the
+ // scrollbars in overlay mode
+ skin.invalidateDisplayList();
+
+ // make sure our alpha is set back to normal from hideScrollBarAnimation
+ if (hideScrollBarAnimation && hideScrollBarAnimation.isPlaying)
+ {
+ // stop the effect, but make sure our code for EFFECT_END doesn't actually
+ // run since the effect didn't end on its own.
+ hideScrollBarAnimationPrematurelyStopped = true;
+ hideScrollBarAnimation.stop();
+ }
+
+ // We only show want the scroll bars to be visible if some content might actually be
+ // off screen. We determine this by looking at the min/max scroll positions.
+ if (horizontalScrollBar)
+ horizontalScrollBar.alpha = (maxHorizontalScrollPosition == 0 && minHorizontalScrollPosition == 0) ? 0.0 : 1.0;
+
+ if (verticalScrollBar)
+ verticalScrollBar.alpha = (maxVerticalScrollPosition == 0 && minVerticalScrollPosition == 0) ? 0.0 : 1.0;
+
+ inTouchInteraction = true;
+ }
+ } */
+
+ /**
+ * @private
+ * Snap the scroll positions to valid values.
+ */
+ /* private function snapContentScrollPosition(snapHorizontal:Boolean = true, snapVertical:Boolean = true):void
+ {
+ // Note that we only snap the scroll position if content is present. This allows existing scroll position
+ // values to be retained before content is added or when it is removed/readded.
+ if (snapHorizontal && viewport.contentWidth != 0)
+ {
+ viewport.horizontalScrollPosition = getSnappedPosition(
+ Math.min(Math.max(minHorizontalScrollPosition, viewport.horizontalScrollPosition), maxHorizontalScrollPosition),
+ HORIZONTAL_SCROLL_POSITION);
+ }
+
+ if (snapVertical && viewport.contentHeight != 0)
+ {
+ viewport.verticalScrollPosition = getSnappedPosition(
+ Math.min(Math.max(minVerticalScrollPosition, viewport.verticalScrollPosition), maxVerticalScrollPosition),
+ VERTICAL_SCROLL_POSITION);
+ }
+ } */
+
+ /**
+ * @private
+ * Stop the effect if it's currently playing and prepare for a possible scroll
+ */
+ /* private function stopThrowEffectOnMouseDown():void
+ {
+ if (throwEffect && throwEffect.isPlaying)
+ {
+ // stop the effect. we don't want to move it to its final value...we want to stop it in place
+ stoppedPreemptively = true;
+ throwEffect.stop();
+
+ // Snap the scroll position to the content in case the empty space beyond the edge was visible
+ // due to bounce/pull.
+ snapContentScrollPosition();
+
+ // get new values in case we start scrolling again
+ hspBeforeTouchScroll = viewport.horizontalScrollPosition;
+ vspBeforeTouchScroll = viewport.verticalScrollPosition;
+ }
+ } */
+
+ /**
+ * @private
+ * Event listeners added while a scroll/throw animation is in effect
+ */
+ /* private function touchScrolling_captureMouseHandler(event:MouseEvent):void
+ {
+ switch(event.type)
+ {
+ case MouseEvent.MOUSE_DOWN:
+ // If we get a mouse down when the throw animation is within a few
+ // pixels of its final destination, we'll go ahead and stop the
+ // touch interaction and allow the event propogation to continue
+ // so other handlers can see it. Otherwise, we'll capture the
+ // down event and start watching for the next scroll.
+
+ // 5 pixels at 252dpi worked fairly well for this heuristic.
+ const THRESHOLD_INCHES:Number = 0.01984; // 5/252
+ var captureThreshold:Number = Math.round(THRESHOLD_INCHES * Capabilities.screenDPI);
+
+ // Need to convert the pixel delta to the local coordinate system in
+ // order to compare it to a scroll position delta.
+ captureThreshold = globalToLocal(
+ new Point(captureThreshold,0)).subtract(globalToLocal(ZERO_POINT)).x;
+
+ if (captureNextMouseDown &&
+ (Math.abs(viewport.verticalScrollPosition - throwFinalVSP) > captureThreshold ||
+ Math.abs(viewport.horizontalScrollPosition - throwFinalHSP) > captureThreshold))
+ {
+ // Capture the down event.
+ stopThrowEffectOnMouseDown();
+
+ // Watch for a scroll to begin. The helper object will call our
+ // performDrag and performThrow callbacks as appropriate.
+ touchScrollHelper.startScrollWatch(
+ event,
+ canScrollHorizontally,
+ canScrollVertically,
+ Math.round(minSlopInches * Capabilities.screenDPI),
+ dragEventThinning ? _maxDragRate : NaN);
+ event.stopImmediatePropagation();
+ }
+ else
+ {
+ // Stop the current throw and allow the down event
+ // to propogate normally.
+ if (throwEffect && throwEffect.isPlaying)
+ {
+ throwEffect.stop();
+ snapContentScrollPosition();
+ }
+ }
+ break;
+ case MouseEvent.CLICK:
+ if (!captureNextClick)
+ return;
+
+ event.stopImmediatePropagation();
+ break;
+ }
+ } */
+
+ /**
+ * @private
+ * Mousedown listener that adds the other listeners to watch for a scroll.
+ */
+ /* private function mouseDownHandler(event:MouseEvent):void
+ {
+ stopThrowEffectOnMouseDown();
+
+ // If the snap animation is playing, we need to stop it
+ // before watching for a scroll and potentially beginning
+ // a new touch interaction.
+ if (snapElementAnimation && snapElementAnimation.isPlaying)
+ {
+ snapElementAnimation.stop();
+
+ // If paging is enabled and the user interrupted the snap animation,
+ // we need to set the current page to where the animation was stopped.
+ if (pageScrollingEnabled)
+ determineCurrentPageScrollPosition();
+ }
+
+ captureNextClick = false;
+
+ // Watch for a scroll to begin. The helper object will call our
+ // performDrag and performThrow callbacks as appropriate.
+ touchScrollHelper.startScrollWatch(
+ event,
+ canScrollHorizontally,
+ canScrollVertically,
+ Math.round(minSlopInches * Capabilities.screenDPI),
+ dragEventThinning ? _maxDragRate : NaN);
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function performDrag(dragX:Number, dragY:Number):void
+ {
+ if (textSelectionAutoScrollEnabled)
+ {
+ setUpTextSelectionAutoScroll();
+ return;
+ }
+
+ // dragX and dragY are delta value in the global coordinate space.
+ // In order to use them to change the scroll position we must convert
+ // them to the scroller's local coordinate space first.
+ // This code converts the deltas from global to local.
+ var localDragDeltas:Point =
+ globalToLocal(new Point(dragX,dragY)).subtract(globalToLocal(ZERO_POINT));
+ dragX = localDragDeltas.x;
+ dragY = localDragDeltas.y;
+
+ var xMove:int = 0;
+ var yMove:int = 0;
+
+ if (canScrollHorizontally)
+ xMove = dragX;
+
+ if (canScrollVertically)
+ yMove = dragY;
+
+ var newHSP:Number = hspBeforeTouchScroll - xMove;
+ var newVSP:Number = vspBeforeTouchScroll - yMove;
+
+ var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+
+ // If we're pulling the list past its end, we want it to move
+ // only a portion of the finger distance to simulate tension.
+ if (pullEnabled)
+ {
+ if (newHSP < minHorizontalScrollPosition)
+ newHSP = Math.round(minHorizontalScrollPosition + ((newHSP-minHorizontalScrollPosition) * PULL_TENSION_RATIO));
+ if (newHSP > maxHorizontalScrollPosition)
+ newHSP = Math.round(maxHorizontalScrollPosition + ((newHSP-maxHorizontalScrollPosition) * PULL_TENSION_RATIO));
+
+ var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+
+ if (newVSP < minVerticalScrollPosition)
+ newVSP = Math.round(minVerticalScrollPosition + ((newVSP-minVerticalScrollPosition) * PULL_TENSION_RATIO));
+
+ if (newVSP > maxVerticalScrollPosition)
+ newVSP = Math.round(maxVerticalScrollPosition + ((newVSP-maxVerticalScrollPosition) * PULL_TENSION_RATIO));
+
+ // clamp the values here
+ newHSP = Math.min(Math.max(newHSP, -viewportWidth), maxHorizontalScrollPosition+viewportWidth);
+ newVSP = Math.min(Math.max(newVSP, -viewportHeight), maxVerticalScrollPosition+viewportHeight);
+ }
+
+ viewport.horizontalScrollPosition = newHSP;
+ viewport.verticalScrollPosition = newVSP;
+ } */
+
+ /**
+ * @private
+ */
+ /* private function throwEffect_effectEndHandler(event:EffectEvent):void
+ {
+ // if we stopped the effect ourself (because someone pressed down), then let's not consider
+ // this the end
+ if (stoppedPreemptively)
+ return;
+
+ touchScrollHelper.endTouchScroll();
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function performThrow(velocityX:Number, velocityY:Number):void
+ {
+ // Don't throw if we're doing a text selection auto scroll
+ if (textSelectionAutoScrollEnabled)
+ {
+ stopTextSelectionAutoScroll();
+ touchScrollHelper.endTouchScroll();
+ return;
+ }
+
+ // If the soft keyboard is up (or about to come up), or
+ // we're offscreen for some reason, don't start a throw.
+ if (preventThrows || !stage)
+ {
+ touchScrollHelper.endTouchScroll();
+ return;
+ }
+
+ stoppedPreemptively = false;
+
+ // The velocity values are deltas in the global coordinate space.
+ // In order to use them to change the scroll position we must convert
+ // them to the scroller's local coordinate space first.
+ // This code converts the deltas from global to local.
+ //
+ // Note that we scale the velocity values up and then back down around the
+ // calls to globalToLocal. This is because the runtime only returns values
+ // rounded to the nearest 0.05. The velocities are small number (<4.0) with
+ // lots of precision that we don't want to lose. The scaling preserves
+ // a sufficient level of precision for our purposes.
+ var throwVelocity:Point = new Point(velocityX, velocityY);
+ throwVelocity.x *= 100000;
+ throwVelocity.y *= 100000;
+
+ // Because we subtract out the difference between the two coordinate systems' origins,
+ // This is essentially just multiplying by a scaling factor.
+ throwVelocity =
+ this.globalToLocal(throwVelocity).subtract(this.globalToLocal(new Point(0, 0)));
+
+ throwVelocity.x /= 100000;
+ throwVelocity.y /= 100000;
+
+ if (setUpThrowEffect(throwVelocity.x, throwVelocity.y))
+ throwEffect.play();
+ } */
+
+ /**
+ * @private
+ * When the throw is over, no need to listen for mouse events anymore.
+ * Also, use this to hide the scrollbars.
+ */
+/* private function touchInteractionEndHandler(event:TouchInteractionEvent):void
+ {
+ if (event.relatedObject == this)
+ {
+ captureNextMouseDown = false;
+ // don't reset captureNextClick here because touchScrollEnd
+ // may be invoked on mouseUp and mouseClick occurs immediately
+ // after that, so we want to block this next mouseClick
+
+ hideScrollBars();
+ inTouchInteraction = false;
+ }
+ } */
+
+ /**
+ * @private
+ * Called when the effect finishes playing on the scrollbars. This is so ScrollerLayout
+ * can hide the scrollbars completely and go back to controlling its visibility.
+ */
+ /* private function hideScrollBarAnimation_effectEndHandler(event:EffectEvent):void
+ {
+ // distinguish between if we called stop() and if the effect ended naturally
+ if (hideScrollBarAnimationPrematurelyStopped)
+ return;
+
+ // now get rid of the scrollbars visibility
+ horizontalScrollInProgress = false;
+ verticalScrollInProgress = false;
+
+ // need to invalidate the ScrollerLayout object so it'll update the
+ // scrollbars in overlay mode
+ skin.invalidateDisplayList();
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Text selection auto scroll
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * When true, use the text selection scroll behavior instead of the
+ * typical "throw" behavior. This is only used when interactionMode="touch"
+ */
+ /* mx_internal var textSelectionAutoScrollEnabled:Boolean = false;
+ private var textSelectionAutoScrollTimer:Timer;
+ private var minTextSelectionVScrollPos:int = 0;
+ private var maxTextSelectionVScrollPos:int = -1;
+ private var minTextSelectionHScrollPos:int = 0;
+ private var maxTextSelectionHScrollPos:int = -1;
+ private static const TEXT_SELECTION_AUTO_SCROLL_FPS:int = 10; */
+
+ /**
+ * @private
+ * Change scroll behavior when selecting text.
+ */
+ /* mx_internal function enableTextSelectionAutoScroll(enable:Boolean,
+ minHScrollPosition:int = 0, maxHScrollPosition:int = -1,
+ minVScrollPosition:int = 0, maxVScrollPosition:int = -1):void
+ {
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ this.textSelectionAutoScrollEnabled = enable;
+ this.minTextSelectionHScrollPos = minHScrollPosition;
+ this.maxTextSelectionHScrollPos = maxHScrollPosition;
+ this.minTextSelectionVScrollPos = minVScrollPosition;
+ this.maxTextSelectionVScrollPos = maxVScrollPosition;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function setUpTextSelectionAutoScroll():void
+ {
+ if (!textSelectionAutoScrollTimer)
+ {
+ textSelectionAutoScrollTimer = new Timer(1000 / TEXT_SELECTION_AUTO_SCROLL_FPS);
+ textSelectionAutoScrollTimer.addEventListener(TimerEvent.TIMER,
+ textSelectionAutoScrollTimerHandler);
+
+ textSelectionAutoScrollTimer.start();
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function stopTextSelectionAutoScroll():void
+ {
+ if (textSelectionAutoScrollTimer)
+ {
+ textSelectionAutoScrollTimer.stop();
+ textSelectionAutoScrollTimer.removeEventListener(TimerEvent.TIMER,
+ textSelectionAutoScrollTimerHandler);
+ textSelectionAutoScrollTimer = null;
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* private function textSelectionAutoScrollTimerHandler(event:TimerEvent):void
+ {
+ const SLOW_SCROLL_THRESHOLD:int = 12; // Distance from edge to trigger a slow scroll
+ const SLOW_SCROLL_SPEED:int = 20; // Pixels per timer callback to scroll
+ const FAST_SCROLL_THRESHOLD:int = 3; // Distance from edge to trigger a fast scroll
+ const FAST_SCROLL_DELTA:int = 30; // Added to SLOW_SCROLL_SPEED to determine fast speed
+
+ var newVSP:Number = viewport.verticalScrollPosition;
+ var newHSP:Number = viewport.horizontalScrollPosition;
+
+ if (canScrollHorizontally)
+ {
+ if (mouseX > width - SLOW_SCROLL_THRESHOLD)
+ {
+ newHSP += SLOW_SCROLL_SPEED;
+
+ if (mouseX > width - FAST_SCROLL_THRESHOLD)
+ newHSP += FAST_SCROLL_DELTA;
+
+ if (maxTextSelectionHScrollPos != -1 && newHSP > maxTextSelectionHScrollPos)
+ newHSP = maxTextSelectionHScrollPos;
+ }
+
+ if (mouseX < SLOW_SCROLL_THRESHOLD)
+ {
+ newHSP -= SLOW_SCROLL_SPEED;
+
+ if (mouseX < FAST_SCROLL_THRESHOLD)
+ newHSP -= FAST_SCROLL_DELTA;
+
+ if (newHSP < minTextSelectionHScrollPos)
+ newHSP = minTextSelectionHScrollPos;
+ }
+ }
+
+ if (canScrollVertically)
+ {
+ if (mouseY > height - SLOW_SCROLL_THRESHOLD)
+ {
+ newVSP += SLOW_SCROLL_SPEED;
+
+ if (mouseY > height - FAST_SCROLL_THRESHOLD)
+ newVSP += FAST_SCROLL_DELTA;
+
+ if (maxTextSelectionVScrollPos != -1 && newVSP > maxTextSelectionVScrollPos)
+ newVSP = maxTextSelectionVScrollPos;
+ }
+
+ if (mouseY < SLOW_SCROLL_THRESHOLD)
+ {
+ newVSP -= SLOW_SCROLL_SPEED;
+
+ if (mouseY < FAST_SCROLL_THRESHOLD)
+ newVSP -= FAST_SCROLL_DELTA;
+
+ if (newVSP < minTextSelectionVScrollPos)
+ newVSP = minTextSelectionVScrollPos;
+ }
+ }
+
+ if (newHSP != viewport.horizontalScrollPosition)
+ viewport.horizontalScrollPosition = newHSP;
+ if (newVSP != viewport.verticalScrollPosition)
+ viewport.verticalScrollPosition = newVSP;
+ } */
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers: SoftKeyboard Interaction
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ /* private function addedToStageHandler(event:Event):void
+ {
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ {
+ // Note that we listen for orientationChanging in the capture phase. This is done so we get the event
+ // before Application does to ensure that the pre-orientation-change dimensions are still in effect.
+ // On iOS, Application swaps the dimensions and forces a validation in its orientationChanging handler.
+ systemManager.stage.addEventListener("orientationChanging", orientationChangingHandler, true);
+ }
+ } */
+
+ /**
+ * @private
+ */
+ /* private function removedFromStageHandler(event:Event):void
+ {
+ if (getStyle("interactionMode") == InteractionMode.TOUCH)
+ systemManager.stage.removeEventListener("orientationChanging", orientationChangingHandler, true);
+ } */
+
+ /**
+ * @private
+ * Called when the soft keyboard is activated.
+ *
+ * There are three use cases for Scroller and text component interaction
+ *
+ * A. Pressing a TextInput to open up the soft keyboard
+ * B. Pressing in the middle of a TextArea to open up the soft keyboard
+ * C. Pressing in a text component on a device that doesn't support soft keyboard
+ *
+ * For use case A, lastFocusedElementCaretBounds is never set, so we just
+ * call ensureElementIsVisible on the TextInput
+ *
+ * For use case B, we first get a softKeyboard active event in the
+ * capture phase. We then receive a caretBoundsChange event from the
+ * TextArea skin. We store the bounds in lastFocusedElementCaretBounds
+ * and use that value in the call to ensureElementPositionIsVisible in
+ * the softKeyboard activate bubble phase.
+ *
+ * For use case C, we never receive a soft keyboard activate event, so
+ * we just listen for caretBoundsChange.
+ */
+ /* private function softKeyboardActivateHandler(event:SoftKeyboardEvent):void
+ {
+ preventThrows = true;
+
+ // Size of app has changed, so run this logic again
+ var keyboardRect:Rectangle = stage.softKeyboardRect;
+
+ if (keyboardRect.width > 0 && keyboardRect.height > 0)
+ {
+ if (lastFocusedElement && ensureElementIsVisibleForSoftKeyboard &&
+ (keyboardRect.height != oldSoftKeyboardHeight ||
+ keyboardRect.width != oldSoftKeyboardWidth))
+ {
+ // lastFocusedElementCaretBounds might have been set in the
+ // caretBoundsChange event handler
+ if (lastFocusedElementCaretBounds == null)
+ {
+ ensureElementIsVisible(lastFocusedElement);
+ }
+ else
+ {
+ // Only show entire element if we just activated the soft keyboard
+ // If the predictive text bar showed up, we don't want the
+ // the element to jump
+ var isSoftKeyboardActive:Boolean = oldSoftKeyboardHeight > 0 || oldSoftKeyboardWidth > 0;
+ ensureElementPositionIsVisible(lastFocusedElement, lastFocusedElementCaretBounds, !isSoftKeyboardActive);
+ lastFocusedElementCaretBounds = null;
+ }
+ }
+
+ oldSoftKeyboardHeight = keyboardRect.height;
+ oldSoftKeyboardWidth = keyboardRect.width;
+ }
+ } */
+
+ /**
+ * @private
+ * Listen for softKeyboard activate in the capture phase so we know if
+ * we need to delay calling ensureElementPositionIsVisible if we get
+ * a caretBoundsChange event
+ */
+ /* private function softKeyboardActivateCaptureHandler(event:SoftKeyboardEvent):void
+ {
+ var keyboardRect:Rectangle = stage.softKeyboardRect;
+
+ if (keyboardRect.width > 0 && keyboardRect.height > 0)
+ {
+ captureNextCaretBoundsChange = true;
+ }
+ } */
+
+ /**
+ * @private
+ * Called when the soft keyboard is deactivated. Tells the top level
+ * application to resize itself and fix the scroll position if necessary
+ */
+ /* private function softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
+ {
+ // Adjust the scroll position after the application's size is restored.
+ adjustScrollPositionAfterSoftKeyboardDeactivate();
+ oldSoftKeyboardHeight = NaN;
+ oldSoftKeyboardWidth = NaN;
+ preventThrows = false;
+ } */
+
+ /**
+ * @private
+ */
+ /* mx_internal function adjustScrollPositionAfterSoftKeyboardDeactivate():void
+ {
+ // If the throw animation is still playing, stop it.
+ if (throwEffect && throwEffect.isPlaying)
+ throwEffect.stop();
+
+ // Fix the scroll position in case we're off the end from the animation
+ snapContentScrollPosition();
+ } */
+
+ /**
+ * @private
+ *
+ * If we just received a softKeyboardActivate event in the capture phase,
+ * we will wait until the bubble phase to call ensureElementPositionIsVisible
+ * For now, store the caret bounds to be used.
+ */
+ /* private function caretBoundsChangeHandler(event:CaretBoundsChangeEvent):void
+ {
+ if (event.isDefaultPrevented())
+ return;
+
+ event.preventDefault();
+
+ if (captureNextCaretBoundsChange)
+ {
+ lastFocusedElementCaretBounds = event.newCaretBounds;
+ captureNextCaretBoundsChange = false;
+ return;
+ }
+
+ // If caretBounds is changing, minimize the scroll
+ ensureElementPositionIsVisible(lastFocusedElement, event.newCaretBounds, false, false);
+ } */
+}
+
+}
--
To stop receiving notification emails like this one, please contact
alinakazi@apache.org.