All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scaffold.libs_as.feathers.controls.ScrollBar.as Maven / Gradle / Ivy

/*
Feathers
Copyright 2012-2015 Bowler Hat LLC. All Rights Reserved.

This program is free software. You can redistribute and/or modify it in
accordance with the terms of the accompanying license agreement.
*/
package feathers.controls
{
	import feathers.core.FeathersControl;
	import feathers.core.IFeathersControl;
	import feathers.core.IMeasureDisplayObject;
	import feathers.core.IValidating;
	import feathers.core.PropertyProxy;
	import feathers.events.FeathersEventType;
	import feathers.layout.Direction;
	import feathers.skins.IStyleProvider;
	import feathers.utils.math.clamp;
	import feathers.utils.math.roundToNearest;

	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;

	import starling.display.DisplayObject;
	import starling.events.Event;
	import starling.events.Touch;
	import starling.events.TouchEvent;
	import starling.events.TouchPhase;

	/**
	 * Dispatched when the scroll bar's value changes.
	 *
	 * 

The properties of the event object have the following values:

* * * * * * *
PropertyValue
bubblesfalse
currentTargetThe Object that defines the * event listener that handles the event. For example, if you use * myButton.addEventListener() to register an event listener, * myButton is the value of the currentTarget.
datanull
targetThe Object that dispatched the event; * it is not always the Object listening for the event. Use the * currentTarget property to always access the Object * listening for the event.
* * @eventType starling.events.Event.CHANGE */ [Event(name="change",type="starling.events.Event")] /** * Dispatched when the user starts interacting with the scroll bar's thumb, * track, or buttons. * *

The properties of the event object have the following values:

* * * * * * *
PropertyValue
bubblesfalse
currentTargetThe Object that defines the * event listener that handles the event. For example, if you use * myButton.addEventListener() to register an event listener, * myButton is the value of the currentTarget.
datanull
targetThe Object that dispatched the event; * it is not always the Object listening for the event. Use the * currentTarget property to always access the Object * listening for the event.
* * @eventType feathers.events.FeathersEventType.BEGIN_INTERACTION */ [Event(name="beginInteraction",type="starling.events.Event")] /** * Dispatched when the user stops interacting with the scroll bar's thumb, * track, or buttons. * *

The properties of the event object have the following values:

* * * * * * *
PropertyValue
bubblesfalse
currentTargetThe Object that defines the * event listener that handles the event. For example, if you use * myButton.addEventListener() to register an event listener, * myButton is the value of the currentTarget.
datanull
targetThe Object that dispatched the event; * it is not always the Object listening for the event. Use the * currentTarget property to always access the Object * listening for the event.
* * @eventType feathers.events.FeathersEventType.END_INTERACTION */ [Event(name="endInteraction",type="starling.events.Event")] /** * Select a value between a minimum and a maximum by dragging a thumb over * a physical range or by using step buttons. This is a desktop-centric * scroll bar with many skinnable parts. For mobile, the * SimpleScrollBar is probably a better choice as it provides * only the thumb to indicate position without all the extra chrome. * *

The following example updates a list to use scroll bars:

* * * list.horizontalScrollBarFactory = function():IScrollBar * { * return new ScrollBar(); * }; * list.verticalScrollBarFactory = function():IScrollBar * { * return new ScrollBar(); * }; * * @see ../../../help/scroll-bar.html How to use the Feathers ScrollBar component * @see feathers.controls.SimpleScrollBar */ public class ScrollBar extends FeathersControl implements IDirectionalScrollBar { /** * @private */ private static const HELPER_POINT:Point = new Point(); /** * @private */ protected static const INVALIDATION_FLAG_THUMB_FACTORY:String = "thumbFactory"; /** * @private */ protected static const INVALIDATION_FLAG_MINIMUM_TRACK_FACTORY:String = "minimumTrackFactory"; /** * @private */ protected static const INVALIDATION_FLAG_MAXIMUM_TRACK_FACTORY:String = "maximumTrackFactory"; /** * @private */ protected static const INVALIDATION_FLAG_DECREMENT_BUTTON_FACTORY:String = "decrementButtonFactory"; /** * @private */ protected static const INVALIDATION_FLAG_INCREMENT_BUTTON_FACTORY:String = "incrementButtonFactory"; /** * @private * DEPRECATED: Replaced by feathers.layout.Direction.HORIZONTAL. * *

DEPRECATION WARNING: This constant is deprecated * starting with Feathers 3.0. It will be removed in a future version of * Feathers according to the standard * Feathers deprecation policy.

*/ public static const DIRECTION_HORIZONTAL:String = "horizontal"; /** * @private * DEPRECATED: Replaced by feathers.layout.Direction.VERTICAL. * *

DEPRECATION WARNING: This constant is deprecated * starting with Feathers 3.0. It will be removed in a future version of * Feathers according to the standard * Feathers deprecation policy.

*/ public static const DIRECTION_VERTICAL:String = "vertical"; /** * @private * DEPRECATED: Replaced by feathers.controls.TrackLayoutMode.SINGLE. * *

DEPRECATION WARNING: This constant is deprecated * starting with Feathers 3.0. It will be removed in a future version of * Feathers according to the standard * Feathers deprecation policy.

*/ public static const TRACK_LAYOUT_MODE_SINGLE:String = "single"; /** * @private * DEPRECATED: Replaced by feathers.controls.TrackLayoutMode.SPLIT. * *

DEPRECATION WARNING: This constant is deprecated * starting with Feathers 3.0. It will be removed in a future version of * Feathers according to the standard * Feathers deprecation policy.

*/ public static const TRACK_LAYOUT_MODE_MIN_MAX:String = "minMax"; /** * The default value added to the styleNameList of the minimum * track. * * @see feathers.core.FeathersControl#styleNameList */ public static const DEFAULT_CHILD_STYLE_NAME_MINIMUM_TRACK:String = "feathers-scroll-bar-minimum-track"; /** * The default value added to the styleNameList of the maximum * track. * * @see feathers.core.FeathersControl#styleNameList */ public static const DEFAULT_CHILD_STYLE_NAME_MAXIMUM_TRACK:String = "feathers-scroll-bar-maximum-track"; /** * The default value added to the styleNameList of the thumb. * * @see feathers.core.FeathersControl#styleNameList */ public static const DEFAULT_CHILD_STYLE_NAME_THUMB:String = "feathers-scroll-bar-thumb"; /** * The default value added to the styleNameList of the decrement * button. * * @see feathers.core.FeathersControl#styleNameList */ public static const DEFAULT_CHILD_STYLE_NAME_DECREMENT_BUTTON:String = "feathers-scroll-bar-decrement-button"; /** * The default value added to the styleNameList of the increment * button. * * @see feathers.core.FeathersControl#styleNameList */ public static const DEFAULT_CHILD_STYLE_NAME_INCREMENT_BUTTON:String = "feathers-scroll-bar-increment-button"; /** * The default IStyleProvider for all ScrollBar * components. * * @default null * @see feathers.core.FeathersControl#styleProvider */ public static var globalStyleProvider:IStyleProvider; /** * @private */ protected static function defaultThumbFactory():Button { return new Button(); } /** * @private */ protected static function defaultMinimumTrackFactory():Button { return new Button(); } /** * @private */ protected static function defaultMaximumTrackFactory():Button { return new Button(); } /** * @private */ protected static function defaultDecrementButtonFactory():Button { return new Button(); } /** * @private */ protected static function defaultIncrementButtonFactory():Button { return new Button(); } /** * Constructor. */ public function ScrollBar() { super(); this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); } /** * The value added to the styleNameList of the minimum * track. This variable is protected so that sub-classes * can customize the minimum track style name in their constructors * instead of using the default style name defined by * DEFAULT_CHILD_STYLE_NAME_MINIMUM_TRACK. * *

To customize the minimum track style name without subclassing, see * customMinimumTrackStyleName.

* * @see #customMinimumTrackStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var minimumTrackStyleName:String = DEFAULT_CHILD_STYLE_NAME_MINIMUM_TRACK; /** * The value added to the styleNameList of the maximum * track. This variable is protected so that sub-classes * can customize the maximum track style name in their constructors * instead of using the default style name defined by * DEFAULT_CHILD_STYLE_NAME_MAXIMUM_TRACK. * *

To customize the maximum track style name without subclassing, see * customMaximumTrackStyleName.

* * @see #customMaximumTrackStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var maximumTrackStyleName:String = DEFAULT_CHILD_STYLE_NAME_MAXIMUM_TRACK; /** * The value added to the styleNameList of the thumb. This * variable is protected so that sub-classes can customize * the thumb style name in their constructors instead of using the * default style name defined by DEFAULT_CHILD_STYLE_NAME_THUMB. * *

To customize the thumb style name without subclassing, see * customThumbStyleName.

* * @see #customThumbStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var thumbStyleName:String = DEFAULT_CHILD_STYLE_NAME_THUMB; /** * The value added to the styleNameList of the decrement * button. This variable is protected so that sub-classes * can customize the decrement button style name in their constructors * instead of using the default style name defined by * DEFAULT_CHILD_STYLE_NAME_DECREMENT_BUTTON. * *

To customize the decrement button style name without subclassing, * see customDecrementButtonStyleName.

* * @see #customDecrementButtonStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var decrementButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_DECREMENT_BUTTON; /** * The value added to the styleNameList of the increment * button. This variable is protected so that sub-classes * can customize the increment button style name in their constructors * instead of using the default style name defined by * DEFAULT_CHILD_STYLE_NAME_INCREMENT_BUTTON. * *

To customize the increment button style name without subclassing, * see customIncrementButtonName.

* * @see #customIncrementButtonStyleName * @see feathers.core.FeathersControl#styleNameList */ protected var incrementButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_INCREMENT_BUTTON; /** * @private */ protected var thumbOriginalWidth:Number = NaN; /** * @private */ protected var thumbOriginalHeight:Number = NaN; /** * @private */ protected var minimumTrackOriginalWidth:Number = NaN; /** * @private */ protected var minimumTrackOriginalHeight:Number = NaN; /** * @private */ protected var maximumTrackOriginalWidth:Number = NaN; /** * @private */ protected var maximumTrackOriginalHeight:Number = NaN; /** * The scroll bar's decrement button sub-component. * *

For internal use in subclasses.

* * @see #decrementButtonFactory * @see #createDecrementButton() */ protected var decrementButton:Button; /** * The scroll bar's increment button sub-component. * *

For internal use in subclasses.

* * @see #incrementButtonFactory * @see #createIncrementButton() */ protected var incrementButton:Button; /** * The scroll bar's thumb sub-component. * *

For internal use in subclasses.

* * @see #thumbFactory * @see #createThumb() */ protected var thumb:DisplayObject; /** * The scroll bar's minimum track sub-component. * *

For internal use in subclasses.

* * @see #minimumTrackFactory * @see #createMinimumTrack() */ protected var minimumTrack:DisplayObject; /** * The scroll bar's maximum track sub-component. * *

For internal use in subclasses.

* * @see #maximumTrackFactory * @see #createMaximumTrack() */ protected var maximumTrack:DisplayObject; /** * @private */ override protected function get defaultStyleProvider():IStyleProvider { return ScrollBar.globalStyleProvider; } /** * @private */ protected var _direction:String = Direction.HORIZONTAL; [Inspectable(type="String",enumeration="horizontal,vertical")] /** * Determines if the scroll bar's thumb can be dragged horizontally or * vertically. When this value changes, the scroll bar's width and * height values do not change automatically. * *

In the following example, the direction is changed to vertical:

* * * scrollBar.direction = Direction.VERTICAL; * * @default feathers.layout.Direction.HORIZONTAL * * @see feathers.layout.Direction#HORIZONTAL * @see feathers.layout.Direction#VERTICAL */ public function get direction():String { return this._direction; } /** * @private */ public function set direction(value:String):void { if(this._direction == value) { return; } this._direction = value; this.invalidate(INVALIDATION_FLAG_DATA); this.invalidate(INVALIDATION_FLAG_DECREMENT_BUTTON_FACTORY); this.invalidate(INVALIDATION_FLAG_INCREMENT_BUTTON_FACTORY); this.invalidate(INVALIDATION_FLAG_MINIMUM_TRACK_FACTORY); this.invalidate(INVALIDATION_FLAG_MAXIMUM_TRACK_FACTORY); this.invalidate(INVALIDATION_FLAG_THUMB_FACTORY); } /** * @private */ protected var _value:Number = 0; /** * @inheritDoc * * @default 0 * * @see #minimum * @see #maximum * @see #step * @see #page * @see #event:change */ public function get value():Number { return this._value; } /** * @private */ public function set value(newValue:Number):void { newValue = clamp(newValue, this._minimum, this._maximum); if(this._value == newValue) { return; } this._value = newValue; this.invalidate(INVALIDATION_FLAG_DATA); if(this.liveDragging || !this.isDragging) { this.dispatchEventWith(Event.CHANGE); } } /** * @private */ protected var _minimum:Number = 0; /** * @inheritDoc * * @default 0 * * @see #value * @see #maximum */ public function get minimum():Number { return this._minimum; } /** * @private */ public function set minimum(value:Number):void { if(this._minimum == value) { return; } this._minimum = value; this.invalidate(INVALIDATION_FLAG_DATA); } /** * @private */ protected var _maximum:Number = 0; /** * @inheritDoc * * @default 0 * * @see #value * @see #minimum */ public function get maximum():Number { return this._maximum; } /** * @private */ public function set maximum(value:Number):void { if(this._maximum == value) { return; } this._maximum = value; this.invalidate(INVALIDATION_FLAG_DATA); } /** * @private */ protected var _step:Number = 0; /** * @inheritDoc * * @default 0 * * @see #value * @see #page */ public function get step():Number { return this._step; } /** * @private */ public function set step(value:Number):void { this._step = value; } /** * @private */ protected var _page:Number = 0; /** * @inheritDoc * * @default 0 * * @see #value * @see #step */ public function get page():Number { return this._page; } /** * @private */ public function set page(value:Number):void { if(this._page == value) { return; } this._page = value; this.invalidate(INVALIDATION_FLAG_DATA); } /** * Quickly sets all padding properties to the same value. The * padding getter always returns the value of * paddingTop, but the other padding values may be * different. * *

In the following example, the padding is changed to 20 pixels:

* * * scrollBar.padding = 20; * * @default 0 * * @see #paddingTop * @see #paddingRight * @see #paddingBottom * @see #paddingLeft */ public function get padding():Number { return this._paddingTop; } /** * @private */ public function set padding(value:Number):void { this.paddingTop = value; this.paddingRight = value; this.paddingBottom = value; this.paddingLeft = value; } /** * @private */ protected var _paddingTop:Number = 0; /** * The minimum space, in pixels, above the content, not * including the track(s). * *

In the following example, the top padding is changed to 20 pixels:

* * * scrollBar.paddingTop = 20; * * @default 0 */ public function get paddingTop():Number { return this._paddingTop; } /** * @private */ public function set paddingTop(value:Number):void { if(this._paddingTop == value) { return; } this._paddingTop = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingRight:Number = 0; /** * The minimum space, in pixels, to the right of the content, not * including the track(s). * *

In the following example, the right padding is changed to 20 pixels:

* * * scrollBar.paddingRight = 20; * * @default 0 */ public function get paddingRight():Number { return this._paddingRight; } /** * @private */ public function set paddingRight(value:Number):void { if(this._paddingRight == value) { return; } this._paddingRight = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingBottom:Number = 0; /** * The minimum space, in pixels, below the content, not * including the track(s). * *

In the following example, the bottom padding is changed to 20 pixels:

* * * scrollBar.paddingBottom = 20; * * @default 0 */ public function get paddingBottom():Number { return this._paddingBottom; } /** * @private */ public function set paddingBottom(value:Number):void { if(this._paddingBottom == value) { return; } this._paddingBottom = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _paddingLeft:Number = 0; /** * The minimum space, in pixels, to the left of the content, not * including the track(s). * *

In the following example, the left padding is changed to 20 pixels:

* * * scrollBar.paddingLeft = 20; * * @default 0 */ public function get paddingLeft():Number { return this._paddingLeft; } /** * @private */ public function set paddingLeft(value:Number):void { if(this._paddingLeft == value) { return; } this._paddingLeft = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var currentRepeatAction:Function; /** * @private */ protected var _repeatTimer:Timer; /** * @private */ protected var _repeatDelay:Number = 0.05; /** * The time, in seconds, before actions are repeated. The first repeat * happens after a delay that is five times longer than the following * repeats. * *

In the following example, the repeat delay is changed to 500 milliseconds:

* * * scrollBar.repeatDelay = 0.5; * * @default 0.05 */ public function get repeatDelay():Number { return this._repeatDelay; } /** * @private */ public function set repeatDelay(value:Number):void { if(this._repeatDelay == value) { return; } this._repeatDelay = value; this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var isDragging:Boolean = false; /** * Determines if the scroll bar dispatches the Event.CHANGE * event every time the thumb moves, or only once it stops moving. * *

In the following example, live dragging is disabled:

* * * scrollBar.liveDragging = false; * * @default true */ public var liveDragging:Boolean = true; /** * @private */ protected var _trackLayoutMode:String = TrackLayoutMode.SINGLE; [Inspectable(type="String",enumeration="single,split")] /** * Determines how the minimum and maximum track skins are positioned and * sized. * *

In the following example, the scroll bar is given two tracks:

* * * scrollBar.trackLayoutMode = TrackLayoutMode.SPLIT; * * @default feathers.controls.TrackLayoutMode.SINGLE * * @see feathers.controls.TrackLayoutMode#SINGLE * @see feathers.controls.TrackLayoutMode#SPLIT */ public function get trackLayoutMode():String { return this._trackLayoutMode; } /** * @private */ public function set trackLayoutMode(value:String):void { if(value === TRACK_LAYOUT_MODE_MIN_MAX) { value = TrackLayoutMode.SPLIT; } if(this._trackLayoutMode == value) { return; } this._trackLayoutMode = value; this.invalidate(INVALIDATION_FLAG_LAYOUT); } /** * @private */ protected var _minimumTrackFactory:Function; /** * A function used to generate the scroll bar's minimum track * sub-component. The minimum track must be an instance of * Button. This factory can be used to change properties on * the minimum track when it is first created. For instance, if you * are skinning Feathers components without a theme, you might use this * factory to set skins and other styles on the minimum track. * *

The function should have the following signature:

*
function():Button
* *

In the following example, a custom minimum track factory is passed * to the scroll bar:

* * * scrollBar.minimumTrackFactory = function():Button * { * var track:Button = new Button(); * track.defaultSkin = new Image( upTexture ); * track.downSkin = new Image( downTexture ); * return track; * }; * * @default null * * @see feathers.controls.Button * @see #minimumTrackProperties */ public function get minimumTrackFactory():Function { return this._minimumTrackFactory; } /** * @private */ public function set minimumTrackFactory(value:Function):void { if(this._minimumTrackFactory == value) { return; } this._minimumTrackFactory = value; this.invalidate(INVALIDATION_FLAG_MINIMUM_TRACK_FACTORY); } /** * @private */ protected var _customMinimumTrackStyleName:String; /** * A style name to add to the scroll bar's minimum track sub-component. * Typically used by a theme to provide different styles to different * scroll bars. * *

In the following example, a custom minimum track style name is * passed to the scroll bar:

* * * scrollBar.customMinimumTrackStyleName = "my-custom-minimum-track"; * *

In your theme, you can target this sub-component style name to provide * different styles than the default:

* * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-minimum-track", setCustomMinimumTrackStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_MINIMUM_TRACK * @see feathers.core.FeathersControl#styleNameList * @see #minimumTrackFactory * @see #minimumTrackProperties */ public function get customMinimumTrackStyleName():String { return this._customMinimumTrackStyleName; } /** * @private */ public function set customMinimumTrackStyleName(value:String):void { if(this._customMinimumTrackStyleName == value) { return; } this._customMinimumTrackStyleName = value; this.invalidate(INVALIDATION_FLAG_MINIMUM_TRACK_FACTORY); } /** * @private */ protected var _minimumTrackProperties:PropertyProxy; /** * An object that stores properties for the scroll bar's "minimum" * track, and the properties will be passed down to the "minimum" track when * the scroll bar validates. For a list of available properties, refer to * feathers.controls.Button. * *

If the subcomponent has its own subcomponents, their properties * can be set too, using attribute @ notation. For example, * to set the skin on the thumb which is in a SimpleScrollBar, * which is in a List, you can use the following syntax:

*
list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
* *

Setting properties in a minimumTrackFactory function * instead of using minimumTrackProperties will result in * better performance.

* *

In the following example, the scroll bar's minimum track properties * are updated:

* * * scrollBar.minimumTrackProperties.defaultSkin = new Image( upTexture ); * scrollBar.minimumTrackProperties.downSkin = new Image( downTexture ); * * @default null * * @see #minimumTrackFactory * @see feathers.controls.Button */ public function get minimumTrackProperties():Object { if(!this._minimumTrackProperties) { this._minimumTrackProperties = new PropertyProxy(minimumTrackProperties_onChange); } return this._minimumTrackProperties; } /** * @private */ public function set minimumTrackProperties(value:Object):void { if(this._minimumTrackProperties == value) { return; } if(!value) { value = new PropertyProxy(); } if(!(value is PropertyProxy)) { var newValue:PropertyProxy = new PropertyProxy(); for(var propertyName:String in value) { newValue[propertyName] = value[propertyName]; } value = newValue; } if(this._minimumTrackProperties) { this._minimumTrackProperties.removeOnChangeCallback(minimumTrackProperties_onChange); } this._minimumTrackProperties = PropertyProxy(value); if(this._minimumTrackProperties) { this._minimumTrackProperties.addOnChangeCallback(minimumTrackProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _maximumTrackFactory:Function; /** * A function used to generate the scroll bar's maximum track * sub-component. The maximum track must be an instance of * Button. This factory can be used to change properties on * the maximum track when it is first created. For instance, if you * are skinning Feathers components without a theme, you might use this * factory to set skins and other styles on the maximum track. * *

The function should have the following signature:

*
function():Button
* *

In the following example, a custom maximum track factory is passed * to the scroll bar:

* * * scrollBar.maximumTrackFactory = function():Button * { * var track:Button = new Button(); * track.defaultSkin = new Image( upTexture ); * track.downSkin = new Image( downTexture ); * return track; * }; * * @default null * * @see feathers.controls.Button * @see #maximumTrackProperties */ public function get maximumTrackFactory():Function { return this._maximumTrackFactory; } /** * @private */ public function set maximumTrackFactory(value:Function):void { if(this._maximumTrackFactory == value) { return; } this._maximumTrackFactory = value; this.invalidate(INVALIDATION_FLAG_MAXIMUM_TRACK_FACTORY); } /** * @private */ protected var _customMaximumTrackStyleName:String; /** * A style name to add to the scroll bar's maximum track sub-component. * Typically used by a theme to provide different styles to different * scroll bars. * *

In the following example, a custom maximum track style name is * passed to the scroll bar:

* * * scrollBar.customMaximumTrackStyleName = "my-custom-maximum-track"; * *

In your theme, you can target this sub-component style name to * provide different styles than the default:

* * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-maximum-track", setCustomMaximumTrackStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_MAXIMUM_TRACK * @see feathers.core.FeathersControl#styleNameList * @see #maximumTrackFactory * @see #maximumTrackProperties */ public function get customMaximumTrackStyleName():String { return this._customMaximumTrackStyleName; } /** * @private */ public function set customMaximumTrackStyleName(value:String):void { if(this._customMaximumTrackStyleName == value) { return; } this._customMaximumTrackStyleName = value; this.invalidate(INVALIDATION_FLAG_MAXIMUM_TRACK_FACTORY); } /** * @private */ protected var _maximumTrackProperties:PropertyProxy; /** * An object that stores properties for the scroll bar's "maximum" * track, and the properties will be passed down to the "maximum" track when * the scroll bar validates. For a list of available properties, refer to * feathers.controls.Button. * *

If the subcomponent has its own subcomponents, their properties * can be set too, using attribute @ notation. For example, * to set the skin on the thumb which is in a SimpleScrollBar, * which is in a List, you can use the following syntax:

*
list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
* *

Setting properties in a maximumTrackFactory function * instead of using maximumTrackProperties will result in * better performance.

* *

In the following example, the scroll bar's maximum track properties * are updated:

* * * scrollBar.maximumTrackProperties.defaultSkin = new Image( upTexture ); * scrollBar.maximumTrackProperties.downSkin = new Image( downTexture ); * * @default null * * @see #maximumTrackFactory * @see feathers.controls.Button */ public function get maximumTrackProperties():Object { if(!this._maximumTrackProperties) { this._maximumTrackProperties = new PropertyProxy(maximumTrackProperties_onChange); } return this._maximumTrackProperties; } /** * @private */ public function set maximumTrackProperties(value:Object):void { if(this._maximumTrackProperties == value) { return; } if(!value) { value = new PropertyProxy(); } if(!(value is PropertyProxy)) { var newValue:PropertyProxy = new PropertyProxy(); for(var propertyName:String in value) { newValue[propertyName] = value[propertyName]; } value = newValue; } if(this._maximumTrackProperties) { this._maximumTrackProperties.removeOnChangeCallback(maximumTrackProperties_onChange); } this._maximumTrackProperties = PropertyProxy(value); if(this._maximumTrackProperties) { this._maximumTrackProperties.addOnChangeCallback(maximumTrackProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _thumbFactory:Function; /** * A function used to generate the scroll bar's thumb sub-component. * The thumb must be an instance of Button. This factory * can be used to change properties on the thumb when it is first * created. For instance, if you are skinning Feathers components * without a theme, you might use this factory to set skins and other * styles on the thumb. * *

The function should have the following signature:

*
function():Button
* *

In the following example, a custom thumb factory is passed * to the scroll bar:

* * * scrollBar.thumbFactory = function():Button * { * var thumb:Button = new Button(); * thumb.defaultSkin = new Image( upTexture ); * thumb.downSkin = new Image( downTexture ); * return thumb; * }; * * @default null * * @see feathers.controls.Button * @see #thumbProperties */ public function get thumbFactory():Function { return this._thumbFactory; } /** * @private */ public function set thumbFactory(value:Function):void { if(this._thumbFactory == value) { return; } this._thumbFactory = value; this.invalidate(INVALIDATION_FLAG_THUMB_FACTORY); } /** * @private */ protected var _customThumbStyleName:String; /** * A style name to add to the scroll bar's thumb sub-component. * Typically used by a theme to provide different styles to different * scroll bars. * *

In the following example, a custom thumb style name is passed * to the scroll bar:

* * * scrollBar.customThumbStyleName = "my-custom-thumb"; * *

In your theme, you can target this sub-component style name to * provide different styles than the default:

* * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-thumb", setCustomThumbStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_THUMB * @see feathers.core.FeathersControl#styleNameList * @see #thumbFactory * @see #thumbProperties */ public function get customThumbStyleName():String { return this._customThumbStyleName; } /** * @private */ public function set customThumbStyleName(value:String):void { if(this._customThumbStyleName == value) { return; } this._customThumbStyleName = value; this.invalidate(INVALIDATION_FLAG_THUMB_FACTORY); } /** * @private */ protected var _thumbProperties:PropertyProxy; /** * An object that stores properties for the scroll bar's thumb, and the * properties will be passed down to the thumb when the scroll bar * validates. For a list of available properties, refer to * feathers.controls.Button. * *

If the subcomponent has its own subcomponents, their properties * can be set too, using attribute @ notation. For example, * to set the skin on the thumb which is in a SimpleScrollBar, * which is in a List, you can use the following syntax:

*
list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
* *

Setting properties in a thumbFactory function instead * of using thumbProperties will result in better * performance.

* *

In the following example, the scroll bar's thumb properties * are updated:

* * * scrollBar.thumbProperties.defaultSkin = new Image( upTexture ); * scrollBar.thumbProperties.downSkin = new Image( downTexture ); * * @default null * * @see #thumbFactory * @see feathers.controls.Button */ public function get thumbProperties():Object { if(!this._thumbProperties) { this._thumbProperties = new PropertyProxy(thumbProperties_onChange); } return this._thumbProperties; } /** * @private */ public function set thumbProperties(value:Object):void { if(this._thumbProperties == value) { return; } if(!value) { value = new PropertyProxy(); } if(!(value is PropertyProxy)) { var newValue:PropertyProxy = new PropertyProxy(); for(var propertyName:String in value) { newValue[propertyName] = value[propertyName]; } value = newValue; } if(this._thumbProperties) { this._thumbProperties.removeOnChangeCallback(thumbProperties_onChange); } this._thumbProperties = PropertyProxy(value); if(this._thumbProperties) { this._thumbProperties.addOnChangeCallback(thumbProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _decrementButtonFactory:Function; /** * A function used to generate the scroll bar's decrement button * sub-component. The decrement button must be an instance of * Button. This factory can be used to change properties on * the decrement button when it is first created. For instance, if you * are skinning Feathers components without a theme, you might use this * factory to set skins and other styles on the decrement button. * *

The function should have the following signature:

*
function():Button
* *

In the following example, a custom decrement button factory is passed * to the scroll bar:

* * * scrollBar.decrementButtonFactory = function():Button * { * var button:Button = new Button(); * button.defaultSkin = new Image( upTexture ); * button.downSkin = new Image( downTexture ); * return button; * }; * * @default null * * @see feathers.controls.Button * @see #decrementButtonProperties */ public function get decrementButtonFactory():Function { return this._decrementButtonFactory; } /** * @private */ public function set decrementButtonFactory(value:Function):void { if(this._decrementButtonFactory == value) { return; } this._decrementButtonFactory = value; this.invalidate(INVALIDATION_FLAG_DECREMENT_BUTTON_FACTORY); } /** * @private */ protected var _customDecrementButtonStyleName:String; /** * A style name to add to the scroll bar's decrement button * sub-component. Typically used by a theme to provide different styles * to different scroll bars. * *

In the following example, a custom decrement button style name is * passed to the scroll bar:

* * * scrollBar.customDecrementButtonStyleName = "my-custom-decrement-button"; * *

In your theme, you can target this sub-component style name to * provide different skins than the default style:

* * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-decrement-button", setCustomDecrementButtonStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_DECREMENT_BUTTON * @see feathers.core.FeathersControl#styleNameList * @see #decrementButtonFactory * @see #decrementButtonProperties */ public function get customDecrementButtonStyleName():String { return this._customDecrementButtonStyleName; } /** * @private */ public function set customDecrementButtonStyleName(value:String):void { if(this._customDecrementButtonStyleName == value) { return; } this._customDecrementButtonStyleName = value; this.invalidate(INVALIDATION_FLAG_DECREMENT_BUTTON_FACTORY); } /** * @private */ protected var _decrementButtonProperties:PropertyProxy; /** * An object that stores properties for the scroll bar's decrement * button, and the properties will be passed down to the decrement * button when the scroll bar validates. For a list of available * properties, refer to * feathers.controls.Button. * *

If the subcomponent has its own subcomponents, their properties * can be set too, using attribute @ notation. For example, * to set the skin on the thumb which is in a SimpleScrollBar, * which is in a List, you can use the following syntax:

*
list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
* *

Setting properties in a decrementButtonFactory * function instead of using decrementButtonProperties will * result in better performance.

* *

In the following example, the scroll bar's decrement button properties * are updated:

* * * scrollBar.decrementButtonProperties.defaultSkin = new Image( upTexture ); * scrollBar.decrementButtonProperties.downSkin = new Image( downTexture ); * * @default null * * @see #decrementButtonFactory * @see feathers.controls.Button */ public function get decrementButtonProperties():Object { if(!this._decrementButtonProperties) { this._decrementButtonProperties = new PropertyProxy(decrementButtonProperties_onChange); } return this._decrementButtonProperties; } /** * @private */ public function set decrementButtonProperties(value:Object):void { if(this._decrementButtonProperties == value) { return; } if(!value) { value = new PropertyProxy(); } if(!(value is PropertyProxy)) { var newValue:PropertyProxy = new PropertyProxy(); for(var propertyName:String in value) { newValue[propertyName] = value[propertyName]; } value = newValue; } if(this._decrementButtonProperties) { this._decrementButtonProperties.removeOnChangeCallback(decrementButtonProperties_onChange); } this._decrementButtonProperties = PropertyProxy(value); if(this._decrementButtonProperties) { this._decrementButtonProperties.addOnChangeCallback(decrementButtonProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _incrementButtonFactory:Function; /** * A function used to generate the scroll bar's increment button * sub-component. The increment button must be an instance of * Button. This factory can be used to change properties on * the increment button when it is first created. For instance, if you * are skinning Feathers components without a theme, you might use this * factory to set skins and other styles on the increment button. * *

The function should have the following signature:

*
function():Button
* *

In the following example, a custom increment button factory is passed * to the scroll bar:

* * * scrollBar.incrementButtonFactory = function():Button * { * var button:Button = new Button(); * button.defaultSkin = new Image( upTexture ); * button.downSkin = new Image( downTexture ); * return button; * }; * * @default null * * @see feathers.controls.Button * @see #incrementButtonProperties */ public function get incrementButtonFactory():Function { return this._incrementButtonFactory; } /** * @private */ public function set incrementButtonFactory(value:Function):void { if(this._incrementButtonFactory == value) { return; } this._incrementButtonFactory = value; this.invalidate(INVALIDATION_FLAG_INCREMENT_BUTTON_FACTORY); } /** * @private */ protected var _customIncrementButtonStyleName:String; /** * A style name to add to the scroll bar's increment button * sub-component. Typically used by a theme to provide different styles * to different scroll bars. * *

In the following example, a custom increment button style name is * passed to the scroll bar:

* * * scrollBar.customIncrementButtonStyleName = "my-custom-increment-button"; * *

In your theme, you can target this sub-component style name to * provide different styles than the default:

* * * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-increment-button", setCustomIncrementButtonStyles ); * * @default null * * @see #DEFAULT_CHILD_STYLE_NAME_INCREMENT_BUTTON * @see feathers.core.FeathersControl#styleNameList * @see #incrementButtonFactory * @see #incrementButtonProperties */ public function get customIncrementButtonStyleName():String { return this._customIncrementButtonStyleName; } /** * @private */ public function set customIncrementButtonStyleName(value:String):void { if(this._customIncrementButtonStyleName == value) { return; } this._customIncrementButtonStyleName = value; this.invalidate(INVALIDATION_FLAG_INCREMENT_BUTTON_FACTORY); } /** * @private */ protected var _incrementButtonProperties:PropertyProxy; /** * An object that stores properties for the scroll bar's increment * button, and the properties will be passed down to the increment * button when the scroll bar validates. For a list of available * properties, refer to * feathers.controls.Button. * *

If the subcomponent has its own subcomponents, their properties * can be set too, using attribute @ notation. For example, * to set the skin on the thumb which is in a SimpleScrollBar, * which is in a List, you can use the following syntax:

*
list.verticalScrollBarProperties.@thumbProperties.defaultSkin = new Image(texture);
* *

Setting properties in a incrementButtonFactory * function instead of using incrementButtonProperties will * result in better performance.

* *

In the following example, the scroll bar's increment button properties * are updated:

* * * scrollBar.incrementButtonProperties.defaultSkin = new Image( upTexture ); * scrollBar.incrementButtonProperties.downSkin = new Image( downTexture ); * * @default null * * @see #incrementButtonFactory * @see feathers.controls.Button */ public function get incrementButtonProperties():Object { if(!this._incrementButtonProperties) { this._incrementButtonProperties = new PropertyProxy(incrementButtonProperties_onChange); } return this._incrementButtonProperties; } /** * @private */ public function set incrementButtonProperties(value:Object):void { if(this._incrementButtonProperties == value) { return; } if(!value) { value = new PropertyProxy(); } if(!(value is PropertyProxy)) { var newValue:PropertyProxy = new PropertyProxy(); for(var propertyName:String in value) { newValue[propertyName] = value[propertyName]; } value = newValue; } if(this._incrementButtonProperties) { this._incrementButtonProperties.removeOnChangeCallback(incrementButtonProperties_onChange); } this._incrementButtonProperties = PropertyProxy(value); if(this._incrementButtonProperties) { this._incrementButtonProperties.addOnChangeCallback(incrementButtonProperties_onChange); } this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected var _touchPointID:int = -1; /** * @private */ protected var _touchStartX:Number = NaN; /** * @private */ protected var _touchStartY:Number = NaN; /** * @private */ protected var _thumbStartX:Number = NaN; /** * @private */ protected var _thumbStartY:Number = NaN; /** * @private */ protected var _touchValue:Number; /** * @private */ override protected function initialize():void { if(this._value < this._minimum) { this.value = this._minimum; } else if(this._value > this._maximum) { this.value = this._maximum; } } /** * @private */ override protected function draw():void { var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA); var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES); var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE); var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE); var layoutInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_LAYOUT); var thumbFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_THUMB_FACTORY); var minimumTrackFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_MINIMUM_TRACK_FACTORY); var maximumTrackFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_MAXIMUM_TRACK_FACTORY); var incrementButtonFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_INCREMENT_BUTTON_FACTORY); var decrementButtonFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DECREMENT_BUTTON_FACTORY); if(thumbFactoryInvalid) { this.createThumb(); } if(minimumTrackFactoryInvalid) { this.createMinimumTrack(); } if(maximumTrackFactoryInvalid || layoutInvalid) { this.createMaximumTrack(); } if(decrementButtonFactoryInvalid) { this.createDecrementButton(); } if(incrementButtonFactoryInvalid) { this.createIncrementButton(); } if(thumbFactoryInvalid || stylesInvalid) { this.refreshThumbStyles(); } if(minimumTrackFactoryInvalid || stylesInvalid) { this.refreshMinimumTrackStyles(); } if((maximumTrackFactoryInvalid || stylesInvalid || layoutInvalid) && this.maximumTrack) { this.refreshMaximumTrackStyles(); } if(decrementButtonFactoryInvalid || stylesInvalid) { this.refreshDecrementButtonStyles(); } if(incrementButtonFactoryInvalid || stylesInvalid) { this.refreshIncrementButtonStyles(); } if(dataInvalid || stateInvalid || thumbFactoryInvalid || minimumTrackFactoryInvalid || maximumTrackFactoryInvalid || decrementButtonFactoryInvalid || incrementButtonFactoryInvalid) { this.refreshEnabled(); } sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid; this.layout(); } /** * If the component's dimensions have not been set explicitly, it will * measure its content and determine an ideal size for itself. If the * explicitWidth or explicitHeight member * variables are set, those value will be used without additional * measurement. If one is set, but not the other, the dimension with the * explicit value will not be measured, but the other non-explicit * dimension will still need measurement. * *

Calls setSizeInternal() to set up the * actualWidth and actualHeight member * variables used for layout.

* *

Meant for internal use, and subclasses may override this function * with a custom implementation.

*/ protected function autoSizeIfNeeded():Boolean { if(this.minimumTrackOriginalWidth !== this.minimumTrackOriginalWidth || //isNaN this.minimumTrackOriginalHeight !== this.minimumTrackOriginalHeight) //isNaN { if(this.minimumTrack is IValidating) { IValidating(this.minimumTrack).validate(); } this.minimumTrackOriginalWidth = this.minimumTrack.width; this.minimumTrackOriginalHeight = this.minimumTrack.height; } if(this.maximumTrack) { if(this.maximumTrackOriginalWidth !== this.maximumTrackOriginalWidth || //isNaN this.maximumTrackOriginalHeight !== this.maximumTrackOriginalHeight) //isNaN { if(this.maximumTrack is IValidating) { IValidating(this.maximumTrack).validate(); } this.maximumTrackOriginalWidth = this.maximumTrack.width; this.maximumTrackOriginalHeight = this.maximumTrack.height; } } if(this.thumbOriginalWidth !== this.thumbOriginalWidth || //isNaN this.thumbOriginalHeight !== this.thumbOriginalHeight) //isNaN { if(this.thumb is IValidating) { IValidating(this.thumb).validate(); } this.thumbOriginalWidth = this.thumb.width; this.thumbOriginalHeight = this.thumb.height; } this.decrementButton.validate(); this.incrementButton.validate(); var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN if(!needsWidth && !needsHeight) { return false; } var newWidth:Number = this._explicitWidth; var newHeight:Number = this._explicitHeight; if(needsWidth) { if(this._direction == Direction.VERTICAL) { if(this.maximumTrack) { newWidth = Math.max(this.minimumTrackOriginalWidth, this.maximumTrackOriginalWidth); } else { newWidth = this.minimumTrackOriginalWidth; } } else //horizontal { if(this.maximumTrack) { newWidth = Math.min(this.minimumTrackOriginalWidth, this.maximumTrackOriginalWidth) + this.thumb.width / 2; } else { newWidth = this.minimumTrackOriginalWidth; } newWidth += this.incrementButton.width + this.decrementButton.width; } } if(needsHeight) { if(this._direction == Direction.VERTICAL) { if(this.maximumTrack) { newHeight = Math.min(this.minimumTrackOriginalHeight, this.maximumTrackOriginalHeight) + this.thumb.height / 2; } else { newHeight = this.minimumTrackOriginalHeight; } newHeight += this.incrementButton.height + this.decrementButton.height; } else //horizontal { if(this.maximumTrack) { newHeight = Math.max(this.minimumTrackOriginalHeight, this.maximumTrackOriginalHeight); } else { newHeight = this.minimumTrackOriginalHeight; } } } return this.setSizeInternal(newWidth, newHeight, false); } /** * Creates and adds the thumb sub-component and * removes the old instance, if one exists. * *

Meant for internal use, and subclasses may override this function * with a custom implementation.

* * @see #thumb * @see #thumbFactory * @see #customThumbStyleName */ protected function createThumb():void { if(this.thumb) { this.thumb.removeFromParent(true); this.thumb = null; } var factory:Function = this._thumbFactory != null ? this._thumbFactory : defaultThumbFactory; var thumbStyleName:String = this._customThumbStyleName != null ? this._customThumbStyleName : this.thumbStyleName; var thumb:Button = Button(factory()); thumb.styleNameList.add(thumbStyleName); thumb.keepDownStateOnRollOut = true; thumb.isFocusEnabled = false; thumb.addEventListener(TouchEvent.TOUCH, thumb_touchHandler); this.addChild(thumb); this.thumb = thumb; } /** * Creates and adds the minimumTrack sub-component and * removes the old instance, if one exists. * *

Meant for internal use, and subclasses may override this function * with a custom implementation.

* * @see #minimumTrack * @see #minimumTrackFactory * @see #customMinimumTrackStyleName */ protected function createMinimumTrack():void { if(this.minimumTrack) { this.minimumTrack.removeFromParent(true); this.minimumTrack = null; } var factory:Function = this._minimumTrackFactory != null ? this._minimumTrackFactory : defaultMinimumTrackFactory; var minimumTrackStyleName:String = this._customMinimumTrackStyleName != null ? this._customMinimumTrackStyleName : this.minimumTrackStyleName; var minimumTrack:Button = Button(factory()); minimumTrack.styleNameList.add(minimumTrackStyleName); minimumTrack.keepDownStateOnRollOut = true; minimumTrack.isFocusEnabled = false; minimumTrack.addEventListener(TouchEvent.TOUCH, track_touchHandler); this.addChildAt(minimumTrack, 0); this.minimumTrack = minimumTrack; } /** * Creates and adds the maximumTrack sub-component and * removes the old instance, if one exists. If the maximum track is not * needed, it will not be created. * *

Meant for internal use, and subclasses may override this function * with a custom implementation.

* * @see #maximumTrack * @see #maximumTrackFactory * @see #customMaximumTrackStyleName */ protected function createMaximumTrack():void { if(this._trackLayoutMode == TrackLayoutMode.SPLIT) { if(this.maximumTrack) { this.maximumTrack.removeFromParent(true); this.maximumTrack = null; } var factory:Function = this._maximumTrackFactory != null ? this._maximumTrackFactory : defaultMaximumTrackFactory; var maximumTrackStyleName:String = this._customMaximumTrackStyleName != null ? this._customMaximumTrackStyleName : this.maximumTrackStyleName; var maximumTrack:Button = Button(factory()); maximumTrack.styleNameList.add(maximumTrackStyleName); maximumTrack.keepDownStateOnRollOut = true; maximumTrack.isFocusEnabled = false; maximumTrack.addEventListener(TouchEvent.TOUCH, track_touchHandler); this.addChildAt(maximumTrack, 1); this.maximumTrack = maximumTrack; } else if(this.maximumTrack) //single { this.maximumTrack.removeFromParent(true); this.maximumTrack = null; } } /** * Creates and adds the decrementButton sub-component and * removes the old instance, if one exists. * *

Meant for internal use, and subclasses may override this function * with a custom implementation.

* * @see #decrementButton * @see #decrementButtonFactory * @see #customDecremenButtonStyleName */ protected function createDecrementButton():void { if(this.decrementButton) { this.decrementButton.removeFromParent(true); this.decrementButton = null; } var factory:Function = this._decrementButtonFactory != null ? this._decrementButtonFactory : defaultDecrementButtonFactory; var decrementButtonStyleName:String = this._customDecrementButtonStyleName != null ? this._customDecrementButtonStyleName : this.decrementButtonStyleName; this.decrementButton = Button(factory()); this.decrementButton.styleNameList.add(decrementButtonStyleName); this.decrementButton.keepDownStateOnRollOut = true; this.decrementButton.isFocusEnabled = false; this.decrementButton.addEventListener(TouchEvent.TOUCH, decrementButton_touchHandler); this.addChild(this.decrementButton); } /** * Creates and adds the incrementButton sub-component and * removes the old instance, if one exists. * *

Meant for internal use, and subclasses may override this function * with a custom implementation.

* * @see #incrementButton * @see #incrementButtonFactory * @see #customIncrementButtonStyleName */ protected function createIncrementButton():void { if(this.incrementButton) { this.incrementButton.removeFromParent(true); this.incrementButton = null; } var factory:Function = this._incrementButtonFactory != null ? this._incrementButtonFactory : defaultIncrementButtonFactory; var incrementButtonStyleName:String = this._customIncrementButtonStyleName != null ? this._customIncrementButtonStyleName : this.incrementButtonStyleName; this.incrementButton = Button(factory()); this.incrementButton.styleNameList.add(incrementButtonStyleName); this.incrementButton.keepDownStateOnRollOut = true; this.incrementButton.isFocusEnabled = false; this.incrementButton.addEventListener(TouchEvent.TOUCH, incrementButton_touchHandler); this.addChild(this.incrementButton); } /** * @private */ protected function refreshThumbStyles():void { for(var propertyName:String in this._thumbProperties) { var propertyValue:Object = this._thumbProperties[propertyName]; this.thumb[propertyName] = propertyValue; } } /** * @private */ protected function refreshMinimumTrackStyles():void { for(var propertyName:String in this._minimumTrackProperties) { var propertyValue:Object = this._minimumTrackProperties[propertyName]; this.minimumTrack[propertyName] = propertyValue; } } /** * @private */ protected function refreshMaximumTrackStyles():void { if(!this.maximumTrack) { return; } for(var propertyName:String in this._maximumTrackProperties) { var propertyValue:Object = this._maximumTrackProperties[propertyName]; this.maximumTrack[propertyName] = propertyValue; } } /** * @private */ protected function refreshDecrementButtonStyles():void { for(var propertyName:String in this._decrementButtonProperties) { var propertyValue:Object = this._decrementButtonProperties[propertyName]; this.decrementButton[propertyName] = propertyValue; } } /** * @private */ protected function refreshIncrementButtonStyles():void { for(var propertyName:String in this._incrementButtonProperties) { var propertyValue:Object = this._incrementButtonProperties[propertyName]; this.incrementButton[propertyName] = propertyValue; } } /** * @private */ protected function refreshEnabled():void { var isEnabled:Boolean = this._isEnabled && this._maximum > this._minimum; if(this.thumb is IFeathersControl) { IFeathersControl(this.thumb).isEnabled = isEnabled; } if(this.minimumTrack is IFeathersControl) { IFeathersControl(this.minimumTrack).isEnabled = isEnabled; } if(this.maximumTrack is IFeathersControl) { IFeathersControl(this.maximumTrack).isEnabled = isEnabled; } this.decrementButton.isEnabled = isEnabled; this.incrementButton.isEnabled = isEnabled; } /** * @private */ protected function layout():void { this.layoutStepButtons(); this.layoutThumb(); if(this._trackLayoutMode == TrackLayoutMode.SPLIT) { this.layoutTrackWithMinMax(); } else //single { this.layoutTrackWithSingle(); } } /** * @private */ protected function layoutStepButtons():void { if(this._direction == Direction.VERTICAL) { this.decrementButton.x = (this.actualWidth - this.decrementButton.width) / 2; this.decrementButton.y = 0; this.incrementButton.x = (this.actualWidth - this.incrementButton.width) / 2; this.incrementButton.y = this.actualHeight - this.incrementButton.height; } else { this.decrementButton.x = 0; this.decrementButton.y = (this.actualHeight - this.decrementButton.height) / 2; this.incrementButton.x = this.actualWidth - this.incrementButton.width; this.incrementButton.y = (this.actualHeight - this.incrementButton.height) / 2; } var showButtons:Boolean = this._maximum != this._minimum; this.decrementButton.visible = showButtons; this.incrementButton.visible = showButtons; } /** * @private */ protected function layoutThumb():void { var range:Number = this._maximum - this._minimum; this.thumb.visible = range > 0 && range < Number.POSITIVE_INFINITY && this._isEnabled; if(!this.thumb.visible) { return; } //this will auto-size the thumb, if needed if(this.thumb is IValidating) { IValidating(this.thumb).validate(); } var contentWidth:Number = this.actualWidth - this._paddingLeft - this._paddingRight; var contentHeight:Number = this.actualHeight - this._paddingTop - this._paddingBottom; var adjustedPage:Number = this._page; if(this._page == 0) { adjustedPage = this._step; } if(adjustedPage > range) { adjustedPage = range; } if(this._direction == Direction.VERTICAL) { contentHeight -= (this.decrementButton.height + this.incrementButton.height); var thumbMinHeight:Number = this.thumbOriginalHeight; if(this.thumb is IMeasureDisplayObject) { thumbMinHeight = IMeasureDisplayObject(this.thumb).minHeight; } this.thumb.width = this.thumbOriginalWidth; this.thumb.height = Math.max(thumbMinHeight, contentHeight * adjustedPage / range); var trackScrollableHeight:Number = contentHeight - this.thumb.height; this.thumb.x = this._paddingLeft + (this.actualWidth - this._paddingLeft - this._paddingRight - this.thumb.width) / 2; this.thumb.y = this.decrementButton.height + this._paddingTop + Math.max(0, Math.min(trackScrollableHeight, trackScrollableHeight * (this._value - this._minimum) / range)); } else //horizontal { contentWidth -= (this.decrementButton.width + this.decrementButton.width); var thumbMinWidth:Number = this.thumbOriginalWidth; if(this.thumb is IMeasureDisplayObject) { thumbMinWidth = IMeasureDisplayObject(this.thumb).minWidth; } this.thumb.width = Math.max(thumbMinWidth, contentWidth * adjustedPage / range); this.thumb.height = this.thumbOriginalHeight; var trackScrollableWidth:Number = contentWidth - this.thumb.width; this.thumb.x = this.decrementButton.width + this._paddingLeft + Math.max(0, Math.min(trackScrollableWidth, trackScrollableWidth * (this._value - this._minimum) / range)); this.thumb.y = this._paddingTop + (this.actualHeight - this._paddingTop - this._paddingBottom - this.thumb.height) / 2; } } /** * @private */ protected function layoutTrackWithMinMax():void { var range:Number = this._maximum - this._minimum; this.minimumTrack.touchable = range > 0 && range < Number.POSITIVE_INFINITY; if(this.maximumTrack) { this.maximumTrack.touchable = range > 0 && range < Number.POSITIVE_INFINITY; } var showButtons:Boolean = this._maximum != this._minimum; if(this._direction == Direction.VERTICAL) { this.minimumTrack.x = 0; if(showButtons) { this.minimumTrack.y = this.decrementButton.height; } else { this.minimumTrack.y = 0; } this.minimumTrack.width = this.actualWidth; this.minimumTrack.height = (this.thumb.y + this.thumb.height / 2) - this.minimumTrack.y; this.maximumTrack.x = 0; this.maximumTrack.y = this.minimumTrack.y + this.minimumTrack.height; this.maximumTrack.width = this.actualWidth; if(showButtons) { this.maximumTrack.height = this.actualHeight - this.incrementButton.height - this.maximumTrack.y; } else { this.maximumTrack.height = this.actualHeight - this.maximumTrack.y; } } else //horizontal { if(showButtons) { this.minimumTrack.x = this.decrementButton.width; } else { this.minimumTrack.x = 0; } this.minimumTrack.y = 0; this.minimumTrack.width = (this.thumb.x + this.thumb.width / 2) - this.minimumTrack.x; this.minimumTrack.height = this.actualHeight; this.maximumTrack.x = this.minimumTrack.x + this.minimumTrack.width; this.maximumTrack.y = 0; if(showButtons) { this.maximumTrack.width = this.actualWidth - this.incrementButton.width - this.maximumTrack.x; } else { this.maximumTrack.width = this.actualWidth - this.maximumTrack.x; } this.maximumTrack.height = this.actualHeight; } //final validation to avoid juggler next frame issues if(this.minimumTrack is IValidating) { IValidating(this.minimumTrack).validate(); } if(this.maximumTrack is IValidating) { IValidating(this.maximumTrack).validate(); } } /** * @private */ protected function layoutTrackWithSingle():void { var range:Number = this._maximum - this._minimum; this.minimumTrack.touchable = range > 0 && range < Number.POSITIVE_INFINITY; var showButtons:Boolean = this._maximum != this._minimum; if(this._direction == Direction.VERTICAL) { this.minimumTrack.x = 0; if(showButtons) { this.minimumTrack.y = this.decrementButton.height; } else { this.minimumTrack.y = 0; } this.minimumTrack.width = this.actualWidth; if(showButtons) { this.minimumTrack.height = this.actualHeight - this.minimumTrack.y - this.incrementButton.height; } else { this.minimumTrack.height = this.actualHeight - this.minimumTrack.y; } } else //horizontal { if(showButtons) { this.minimumTrack.x = this.decrementButton.width; } else { this.minimumTrack.x = 0; } this.minimumTrack.y = 0; if(showButtons) { this.minimumTrack.width = this.actualWidth - this.minimumTrack.x - this.incrementButton.width; } else { this.minimumTrack.width = this.actualWidth - this.minimumTrack.x; } this.minimumTrack.height = this.actualHeight; } //final validation to avoid juggler next frame issues if(this.minimumTrack is IValidating) { IValidating(this.minimumTrack).validate(); } } /** * @private */ protected function locationToValue(location:Point):Number { var percentage:Number = 0; if(this._direction == Direction.VERTICAL) { var trackScrollableHeight:Number = this.actualHeight - this.thumb.height - this.decrementButton.height - this.incrementButton.height - this._paddingTop - this._paddingBottom; if(trackScrollableHeight > 0) { var yOffset:Number = location.y - this._touchStartY - this._paddingTop; var yPosition:Number = Math.min(Math.max(0, this._thumbStartY + yOffset - this.decrementButton.height), trackScrollableHeight); percentage = yPosition / trackScrollableHeight; } } else //horizontal { var trackScrollableWidth:Number = this.actualWidth - this.thumb.width - this.decrementButton.width - this.incrementButton.width - this._paddingLeft - this._paddingRight; if(trackScrollableWidth > 0) { var xOffset:Number = location.x - this._touchStartX - this._paddingLeft; var xPosition:Number = Math.min(Math.max(0, this._thumbStartX + xOffset - this.decrementButton.width), trackScrollableWidth); percentage = xPosition / trackScrollableWidth; } } return this._minimum + percentage * (this._maximum - this._minimum); } /** * @private */ protected function decrement():void { this.value -= this._step; } /** * @private */ protected function increment():void { this.value += this._step; } /** * @private */ protected function adjustPage():void { var range:Number = this._maximum - this._minimum; var adjustedPage:Number = this._page; if(this._page == 0) { adjustedPage = this._step; } if(adjustedPage > range) { adjustedPage = range; } if(this._touchValue < this._value) { var newValue:Number = Math.max(this._touchValue, this._value - adjustedPage); if(this._step != 0 && newValue != this._maximum && newValue != this._minimum) { newValue = roundToNearest(newValue, this._step); } this.value = newValue; } else if(this._touchValue > this._value) { newValue = Math.min(this._touchValue, this._value + adjustedPage); if(this._step != 0 && newValue != this._maximum && newValue != this._minimum) { newValue = roundToNearest(newValue, this._step); } this.value = newValue; } } /** * @private */ protected function startRepeatTimer(action:Function):void { this.currentRepeatAction = action; if(this._repeatDelay > 0) { if(!this._repeatTimer) { this._repeatTimer = new Timer(this._repeatDelay * 1000); this._repeatTimer.addEventListener(TimerEvent.TIMER, repeatTimer_timerHandler); } else { this._repeatTimer.reset(); this._repeatTimer.delay = this._repeatDelay * 1000; } this._repeatTimer.start(); } } /** * @private */ protected function thumbProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function minimumTrackProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function maximumTrackProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function decrementButtonProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function incrementButtonProperties_onChange(proxy:PropertyProxy, name:Object):void { this.invalidate(INVALIDATION_FLAG_STYLES); } /** * @private */ protected function removedFromStageHandler(event:Event):void { this._touchPointID = -1; if(this._repeatTimer) { this._repeatTimer.stop(); } } /** * @private */ protected function track_touchHandler(event:TouchEvent):void { if(!this._isEnabled) { this._touchPointID = -1; return; } var track:DisplayObject = DisplayObject(event.currentTarget); if(this._touchPointID >= 0) { var touch:Touch = event.getTouch(track, TouchPhase.ENDED, this._touchPointID); if(!touch) { return; } this._touchPointID = -1; this._repeatTimer.stop(); this.dispatchEventWith(FeathersEventType.END_INTERACTION); } else { touch = event.getTouch(track, TouchPhase.BEGAN); if(!touch) { return; } this._touchPointID = touch.id; this.dispatchEventWith(FeathersEventType.BEGIN_INTERACTION); touch.getLocation(this, HELPER_POINT); this._touchStartX = HELPER_POINT.x; this._touchStartY = HELPER_POINT.y; this._thumbStartX = HELPER_POINT.x; this._thumbStartY = HELPER_POINT.y; this._touchValue = this.locationToValue(HELPER_POINT); this.adjustPage(); this.startRepeatTimer(this.adjustPage); } } /** * @private */ protected function thumb_touchHandler(event:TouchEvent):void { if(!this._isEnabled) { this._touchPointID = -1; return; } if(this._touchPointID >= 0) { var touch:Touch = event.getTouch(this.thumb, null, this._touchPointID); if(!touch) { return; } if(touch.phase == TouchPhase.MOVED) { touch.getLocation(this, HELPER_POINT); var newValue:Number = this.locationToValue(HELPER_POINT); if(this._step != 0 && newValue != this._maximum && newValue != this._minimum) { newValue = roundToNearest(newValue, this._step); } this.value = newValue; } else if(touch.phase == TouchPhase.ENDED) { this._touchPointID = -1; this.isDragging = false; if(!this.liveDragging) { this.dispatchEventWith(Event.CHANGE); } this.dispatchEventWith(FeathersEventType.END_INTERACTION); } } else { touch = event.getTouch(this.thumb, TouchPhase.BEGAN); if(!touch) { return; } touch.getLocation(this, HELPER_POINT); this._touchPointID = touch.id; this._thumbStartX = this.thumb.x; this._thumbStartY = this.thumb.y; this._touchStartX = HELPER_POINT.x; this._touchStartY = HELPER_POINT.y; this.isDragging = true; this.dispatchEventWith(FeathersEventType.BEGIN_INTERACTION); } } /** * @private */ protected function decrementButton_touchHandler(event:TouchEvent):void { if(!this._isEnabled) { this._touchPointID = -1; return; } if(this._touchPointID >= 0) { var touch:Touch = event.getTouch(this.decrementButton, TouchPhase.ENDED, this._touchPointID); if(!touch) { return; } this._touchPointID = -1; this._repeatTimer.stop(); this.dispatchEventWith(FeathersEventType.END_INTERACTION); } else //if we get here, we don't have a saved touch ID yet { touch = event.getTouch(this.decrementButton, TouchPhase.BEGAN); if(!touch) { return; } this._touchPointID = touch.id; this.dispatchEventWith(FeathersEventType.BEGIN_INTERACTION); this.decrement(); this.startRepeatTimer(this.decrement); } } /** * @private */ protected function incrementButton_touchHandler(event:TouchEvent):void { if(!this._isEnabled) { this._touchPointID = -1; return; } if(this._touchPointID >= 0) { var touch:Touch = event.getTouch(this.incrementButton, TouchPhase.ENDED, this._touchPointID); if(!touch) { return; } this._touchPointID = -1; this._repeatTimer.stop(); this.dispatchEventWith(FeathersEventType.END_INTERACTION); } else //if we get here, we don't have a saved touch ID yet { touch = event.getTouch(this.incrementButton, TouchPhase.BEGAN); if(!touch) { return; } this._touchPointID = touch.id; this.dispatchEventWith(FeathersEventType.BEGIN_INTERACTION); this.increment(); this.startRepeatTimer(this.increment); } } /** * @private */ protected function repeatTimer_timerHandler(event:TimerEvent):void { if(this._repeatTimer.currentCount < 5) { return; } this.currentRepeatAction(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy