// Copyright 2007. Adobe Systems Incorporated. All Rights Reserved.
package fl.controls {
import fl.controls.BaseButton;
import fl.controls.SliderDirection;
import fl.controls.ScrollBar;
import fl.core.InvalidationType;
import fl.core.UIComponent;
import fl.events.SliderEvent;
import fl.events.InteractionInputType;
import fl.events.SliderEventClickTarget;
import fl.managers.IFocusManagerComponent;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
//--------------------------------------
// Events
//--------------------------------------
/**
* Dispatched when the slider thumb is pressed.
*
* @eventType fl.events.SliderEvent.THUMB_PRESS
*
* @see #event:thumbDrag
* @see #event:thumbRelease
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Event(name="thumbPress", type="fl.events.SliderEvent")]
/**
* Dispatched when the slider thumb is pressed and released.
*
* @eventType fl.events.SliderEvent.THUMB_RELEASE
*
* @includeExample examples/Slider.thumbRelease.1.as -noswf
*
* @see #event:thumbDrag
* @see #event:thumbPress
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Event(name="thumbRelease", type="fl.events.SliderEvent")]
/**
* Dispatched when the slider thumb is pressed and
* then moved by the mouse. This event is always preceded by a
* thumbPress
event.
*
* @eventType fl.events.SliderEvent.THUMB_DRAG
*
* @includeExample examples/Slider.thumbDrag.1.as -noswf
*
* @see #event:thumbPress
* @see #event:thumbRelease
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Event(name="thumbDrag", type="fl.events.SliderEvent")]
/**
* Dispatched when the value of the Slider component changes as a result of mouse or keyboard
* interaction. If the liveDragging
property is true
, the event is
* dispatched continuously as the user moves the thumb. If
* liveDragging
is false
, the event is dispatched when the user
* releases the slider thumb.
*
* @eventType fl.events.SliderEvent.CHANGE
*
* @see #liveDragging
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Event(name="change", type="fl.events.SliderEvent")]
//--------------------------------------
// Styles
//--------------------------------------
/**
* @copy fl.controls.ScrollBar#style:thumbUpSkin
*
* @default SliderThumb_upSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="thumbUpSkin", type="Class")]
/**
* @copy fl.controls.ScrollBar#style:thumbOverSkin
*
* @default SliderThumb_overSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="thumbOverSkin", type="Class")]
/**
* @copy fl.controls.ScrollBar#style:thumbDownSkin
*
* @default SliderThumb_downSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="thumbDownSkin", type="Class")]
/**
* @copy fl.controls.ScrollBar#style:thumbDisabledSkin
*
* @default SliderThumb_disabledSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="thumbDisabledSkin", type="Class")]
/**
* The skin for the track in a Slider component.
*
* @default SliderTrack_skin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="sliderTrackSkin", type="Class")]
/**
* The skin for the track in a Slider component that is disabled.
*
* @default SliderTrack_disabledSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="sliderTrackDisabledSkin", type="Class")]
/**
* The skin for the ticks in a Slider component.
*
* @default SliderTick_skin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="tickSkin", type="Class")]
//--------------------------------------
// Class description
//--------------------------------------
/**
* The Slider component lets users select a value by moving a slider
* thumb between the end points of the slider track. The current
* value of the Slider component is determined by the relative location of
* the thumb between the end points of the slider, corresponding to
* the minimum
and maximum
values of the Slider
* component.
*
* @includeExample examples/SliderExample.as
*
* @see fl.events.SliderEvent SliderEvent
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public class Slider extends UIComponent implements IFocusManagerComponent {
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _direction:String = SliderDirection.HORIZONTAL;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _minimum:Number = 0;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _maximum:Number = 10;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _value:Number = 0;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _tickInterval:Number = 0;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _snapInterval:Number = 0;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _liveDragging:Boolean = false;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var tickContainer:Sprite;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var thumb:BaseButton;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var track:BaseButton;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static var defaultStyles:Object = {
thumbUpSkin: "SliderThumb_upSkin",
thumbOverSkin : "SliderThumb_overSkin",
thumbDownSkin: "SliderThumb_downSkin",
thumbDisabledSkin: "SliderThumb_disabledSkin",
sliderTrackSkin: "SliderTrack_skin",
sliderTrackDisabledSkin: "SliderTrack_disabledSkin",
tickSkin: "SliderTick_skin",
focusRectSkin:null,
focusRectPadding:null
}
/**
* @copy fl.core.UIComponent#getStyleDefinition()
*
* @includeExample ../core/examples/UIComponent.getStyleDefinition.1.as -noswf
*
* @see fl.core.UIComponent#getStyle() UIComponent.getStyle()
* @see fl.core.UIComponent#setStyle() UIComponent.setStyle()
* @see fl.managers.StyleManager StyleManager
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public static function getStyleDefinition():Object { return defaultStyles; }
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static const TRACK_STYLES:Object = {
upSkin: "sliderTrackSkin",
overSkin: "sliderTrackSkin",
downSkin: "sliderTrackSkin",
disabledSkin: "sliderTrackDisabledSkin"
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static const THUMB_STYLES:Object = {
upSkin: "thumbUpSkin",
overSkin: "thumbOverSkin",
downSkin: "thumbDownSkin",
disabledSkin: "thumbDisabledSkin"
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static const TICK_STYLES:Object = {
upSkin: "tickSkin"
}
/**
* Creates a new Slider component instance.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function Slider() {
super();
setStyles();
}
[Inspectable(enumeration="horizontal,vertical", defaultValue="horizontal")]
/**
* Sets the direction of the slider. Acceptable values are SliderDirection.HORIZONTAL
and
* SliderDirection.VERTICAL
.
*
* @default SliderDirection.HORIZONTAL
*
* @includeExample examples/Slider.direction.1.as -noswf
*
* @see SliderDirection
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get direction():String {
return _direction;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set direction(value:String):void {
_direction = value;
var vertical:Boolean = (_direction == SliderDirection.VERTICAL);
if (isLivePreview) {
if (vertical) {
setScaleY(-1);
y = track.height;
} else {
setScaleY(1);
y = 0;
}
positionThumb();
return;
}
if (vertical && componentInspectorSetting) {
if (rotation % 90 == 0) {
setScaleY(-1);
}
}
if (!componentInspectorSetting) {
rotation = (vertical)?90:0;
}
}
[Inspectable(defaultValue=0)]
/**
* The minimum value allowed on the Slider component instance.
*
* @default 0
*
* @see #maximum
* @see #value
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get minimum():Number { return _minimum; }
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set minimum(value:Number):void {
_minimum = value;
this.value = Math.max(value, this.value);
invalidate(InvalidationType.DATA);
}
[Inspectable(defaultValue=10)]
/**
* The maximum allowed value on the Slider component instance.
*
* @default 10
*
* @see #minimum
* @see #value
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get maximum():Number {
return _maximum;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set maximum(value:Number):void {
_maximum = value;
this.value = Math.min(value, this.value);
invalidate(InvalidationType.DATA);
}
[Inspectable(defaultValue=0)]
/**
* The spacing of the tick marks relative to the maximum value
* of the component. The Slider component displays tick marks whenever
* you set the tickInterval
property to a nonzero value.
*
* @default 0
*
* @see #snapInterval
*
* @includeExample examples/Slider.tickInterval.1.as -noswf
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get tickInterval():Number {
return _tickInterval;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set tickInterval(value:Number):void {
_tickInterval = value;
invalidate(InvalidationType.SIZE);
}
[Inspectable(defaultValue=0)]
/**
* Gets or sets the increment by which the value is increased or decreased
* as the user moves the slider thumb.
*
*
For example, this property is set to 2, the minimum
value is 0,
* and the maximum
value is 10, the position of the thumb will always
* be at 0, 2, 4, 6, 8, or 10. If this property is set to 0, the slider
* moves continuously between the minimum
and maximum
values.
SliderEvent.CHANGE
* event is dispatched continuously as the user moves the slider thumb. If the
* liveDragging
property is false
, the SliderEvent.CHANGE
* event is dispatched when the user releases the slider thumb.
*
* @default false
*
* @includeExample examples/Slider.liveDragging.1.as -noswf
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set liveDragging(value:Boolean):void {
_liveDragging = value;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get liveDragging():Boolean {
return _liveDragging;
}
[Inspectable(defaultValue=true, verbose=1)]
/**
* @copy fl.core.UIComponent#enabled
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function get enabled():Boolean {
return super.enabled;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function set enabled(value:Boolean):void {
if (enabled == value) { return; }
super.enabled = value;
track.enabled = thumb.enabled = value;
}
/**
* @copy fl.core.UIComponent#setSize()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function setSize(w:Number, h:Number):void {
if (_direction == SliderDirection.VERTICAL && !isLivePreview) {
super.setSize(h, w);
} else {
super.setSize(w, h);
}
invalidate(InvalidationType.SIZE);
}
[Inspectable(defaultValue=0)]
/**
* Gets or sets the current value of the Slider component. This value is
* determined by the position of the slider thumb between the minimum and
* maximum values.
*
* @default 0
*
* @see #maximum
* @see #minimum
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get value():Number {
return _value;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set value(value:Number):void {
doSetValue(value);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function doSetValue(val:Number, interactionType:String=null, clickTarget:String=null, keyCode:int=undefined):void {
var oldVal:Number = _value;
if (_snapInterval != 0 && _snapInterval != 1) {
var pow:Number = Math.pow(10, getPrecision(snapInterval));
var snap:Number = _snapInterval * pow;
var rounded:Number = Math.round(val * pow);
var snapped:Number = Math.round(rounded / snap) * snap;
var val:Number = snapped / pow;
_value = Math.max(minimum, Math.min(maximum,val));
} else {
_value = Math.max(minimum, Math.min(maximum, Math.round(val)));
}
// Only dispatch if value has changed
// Dispatch when dragging
if (oldVal != _value && ((liveDragging && clickTarget != null) || (interactionType == InteractionInputType.KEYBOARD))) {
dispatchEvent(new SliderEvent(SliderEvent.CHANGE, value, clickTarget, interactionType, keyCode));
}
positionThumb();
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function setStyles():void {
copyStylesToChild(thumb, THUMB_STYLES);
copyStylesToChild(track, TRACK_STYLES);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override protected function draw():void {
if (isInvalid(InvalidationType.STYLES)) {
setStyles();
invalidate(InvalidationType.SIZE, false);
}
if (isInvalid(InvalidationType.SIZE)) {
track.setSize(_width, track.height);
track.drawNow();
thumb.drawNow();
}
if (tickInterval > 0) {
drawTicks();
} else {
clearTicks();
}
positionThumb();
super.draw();
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function positionThumb():void {
thumb.x = ((_direction == SliderDirection.VERTICAL) ? (maximum-value) : (value-minimum))/(maximum-minimum)*(_width);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function drawTicks():void {
clearTicks();
tickContainer = new Sprite();
var divisor:Number = (maximum<1)?tickInterval/100:tickInterval;
var l:Number = (maximum-minimum)/divisor;
var dist:Number = _width/l;
for (var i:uint=0;i<=l;i++) {
var tick:DisplayObject = getDisplayObjectInstance(getStyleValue("tickSkin"));
tick.x = dist * i;
tick.y = (track.y - tick.height) - 2;
tickContainer.addChild(tick);
}
addChild(tickContainer);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function clearTicks():void {
if (!tickContainer || !tickContainer.parent) { return; }
removeChild(tickContainer);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function calculateValue(pos:Number, interactionType:String, clickTarget:String, keyCode:int = undefined):void {
var newValue:Number = (pos/_width)*(maximum-minimum);
if (_direction == SliderDirection.VERTICAL) {
newValue = (maximum - newValue);
} else {
newValue = (minimum + newValue);
}
doSetValue(newValue, interactionType, clickTarget, keyCode);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function doDrag(event:MouseEvent):void {
var dist:Number = _width/snapInterval;
var thumbPos:Number = track.mouseX;
calculateValue(thumbPos, InteractionInputType.MOUSE, SliderEventClickTarget.THUMB);
dispatchEvent(new SliderEvent(SliderEvent.THUMB_DRAG, value, SliderEventClickTarget.THUMB, InteractionInputType.MOUSE));
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function thumbPressHandler(event:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE,doDrag,false,0,true);
stage.addEventListener(MouseEvent.MOUSE_UP,thumbReleaseHandler,false,0,true);
dispatchEvent(new SliderEvent(SliderEvent.THUMB_PRESS, value, SliderEventClickTarget.THUMB, InteractionInputType.MOUSE));
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function thumbReleaseHandler(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE,doDrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,thumbReleaseHandler);
dispatchEvent(new SliderEvent(SliderEvent.THUMB_RELEASE, value, SliderEventClickTarget.THUMB, InteractionInputType.MOUSE));
dispatchEvent(new SliderEvent(SliderEvent.CHANGE, value, SliderEventClickTarget.THUMB, InteractionInputType.MOUSE));
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function onTrackClick(event:MouseEvent):void {
calculateValue(track.mouseX, InteractionInputType.MOUSE, SliderEventClickTarget.TRACK);
if (!liveDragging) {
dispatchEvent(new SliderEvent(SliderEvent.CHANGE, value, SliderEventClickTarget.TRACK, InteractionInputType.MOUSE));
}
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override protected function keyDownHandler(event:KeyboardEvent):void {
if (!enabled) { return; }
var incrementBy:Number = (snapInterval > 0) ? snapInterval : 1;
var newValue:Number;
var isHorizontal:Boolean = (direction == SliderDirection.HORIZONTAL);
if ((event.keyCode == Keyboard.DOWN && !isHorizontal) || (event.keyCode == Keyboard.LEFT && isHorizontal)) {
newValue = value - incrementBy;
} else if ((event.keyCode == Keyboard.UP && !isHorizontal) || (event.keyCode == Keyboard.RIGHT && isHorizontal)) {
newValue = value + incrementBy;
} else if ((event.keyCode == Keyboard.PAGE_DOWN && !isHorizontal) || (event.keyCode == Keyboard.HOME && isHorizontal)) {
newValue = minimum;
} else if ((event.keyCode == Keyboard.PAGE_UP && !isHorizontal) || (event.keyCode == Keyboard.END && isHorizontal)) {
newValue = maximum;
}
if (!isNaN(newValue)) {
event.stopPropagation();
doSetValue(newValue, InteractionInputType.KEYBOARD, null, event.keyCode);
}
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override protected function configUI():void {
super.configUI();
thumb = new BaseButton();
thumb.setSize(13, 13);
thumb.autoRepeat = false;
addChild(thumb);
thumb.addEventListener(MouseEvent.MOUSE_DOWN,thumbPressHandler,false,0,true);
track = new BaseButton();
track.move(0, 0);
track.setSize(80, 4);
track.autoRepeat = false;
track.useHandCursor = false;
track.addEventListener(MouseEvent.CLICK,onTrackClick,false,0,true);
addChildAt(track,0);
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function getPrecision(num:Number):Number {
var s:String = num.toString();
if (s.indexOf(".") == -1) { return 0; }
return s.split(".").pop().length;
}
}
}