//////////////////////////////////////////////////////////////////////////////// // // 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.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.utils.Timer; import mx.core.IVisualElement; import mx.core.UIComponent; import mx.core.mx_internal; import mx.events.FlexEvent; import mx.events.ResizeEvent; import spark.components.supportClasses.ToggleButtonBase; import spark.core.IDisplayText; import spark.effects.Animate; import spark.effects.animation.Animation; import spark.effects.animation.IAnimationTarget; import spark.effects.animation.MotionPath; import spark.effects.animation.SimpleMotionPath; import spark.effects.easing.Linear; import spark.effects.easing.Sine; import spark.utils.MouseEventUtil; use namespace mx_internal; //-------------------------------------- // Styles //-------------------------------------- /** * Color applied to highlight the selected side of the ToggleSwitch control. * * @default 0x3F7FBA * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ [Style(name="accentColor", type="uint", format="Color", inherit="yes")] /** * The duration, in milleseconds, for an animation of the thumb * as it slides between the selected and unselected sides of the track. * For animations between any two arbitrary positions on the track, * the animation takes a proportionally shorter amount of time. * For example, after dragging the thumb half way along the track, * the animation for the slide the remainder of the way along the track * takes half the duration. * * @default 125 * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ [Style(name="slideDuration", type="Number", format="Time", inherit="no")] /** * The alpha of text shadows. * * @default 0.65 * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ [Style(name="textShadowAlpha", type="Number", inherit="yes", minValue="0.0", maxValue="1.0", theme="mobile")] /** * The color of text shadows. * * @default 0x000000 * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ [Style(name="textShadowColor", type="uint", format="Color", inherit="yes", theme="mobile")] //-------------------------------------- // Excluded APIs //-------------------------------------- [Exclude(name="textAlign", kind="style")] //-------------------------------------- // Other metadata //-------------------------------------- [IconFile("ToggleSwitch.png")] /** * The Spark ToggleSwitch control defines a binary switch that * can be in the selected or unselected position. * The ToggleSwitch consists of a thumb skin part that moves between * the two ends of the track skin part, similar to the Spark Slider control. * *
The ToggleSwitch control has two positions: selected and unselected. * By default, the label OFF corresponds to the unselected position and ON * corresponds to the selected position.
* *The following image shows a ToggleSwitch control. * The labels below the control show the current switch label and position:
* ** *
* *Clicking anywhere in the control toggles the position. * You can also slide the thumb along the track to change position. * When you release the thumb, it moves to the position, selected or unselected, * that is closest to the thumb location.
* *The ToggleSwitch control uses the following default values for * the unselected and selected labels: OFF (unselected) and ON (selected). * Define a custom skin to change the labels, or to change other visual * characteristics of the control.
* *The following skin class, defined as a subclass of * spark.skins.mobile.ToggleSwitchSkin, changes the labels to Yes and No:
* ** package skins * // components\mobile\skins\MyToggleSwitchSkin.as * { * import spark.skins.mobile.ToggleSwitchSkin; * * public class MyToggleSwitchSkin extends ToggleSwitchSkin * { * public function MyToggleSwitchSkin() * { * super(); * // Set properties to define the labels * // for the selected and unselected positions. * selectedLabel="Yes"; * unselectedLabel="No"; * } * } * } ** * @mxml * *
The <s:ToggleSwitch>
tag inherits all of the tag
* attributes of its superclass and adds the following tag attributes:
* <s:ToggleSwitch * Properties * selected="null" * * Common Styles * accentColor="0x3F7FBA" * slideDuration="125" * * Mobile Styles * textShadowAlpha="0.65" * textShadowColor="0x000000" * > ** * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 * * @includeExample examples/ToggleSwitchExample.mxml -noswf * * @see spark.components.ToggleButton * @see spark.components.HSlider * @see spark.skins.mobile.ToggleSwitchSkin */ public class ToggleSwitch extends ToggleButtonBase { //---------------------------------------------------------------------------------------------- // // Class constants // //---------------------------------------------------------------------------------------------- /** * The amount the mouse can move before we consider the event a drag and not a click */ private static const MOUSE_MOVE_TOLERANCE:Number = 0.15; //---------------------------------------------------------------------------------------------- // // Constructor // //---------------------------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ public function ToggleSwitch() { super(); stickyHighlighting = true; animator = new Animation(); addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); } //---------------------------------------------------------------------------------------------- // // Variables // //---------------------------------------------------------------------------------------------- /** * The last position of the mouse during a drag gesture */ private var lastMouseX:Number = 0; /** * Controls the mouse events driving a drag gesture on a * ToggleSwitch */ private var mouseDragUtil:MouseDragUtil; /** * Whether the mouse has moved during the current drag * gesture */ private var mouseMoved:Boolean = false; /** * Where the thumb should be after the current animation ends */ private var slideToPosition:Number = 0; /** * The point where the current mouse gesture began */ private var stageOffset:Point; /** * The thumbPosition when the current mouse gesture began */ private var positionOffset:Number = 0; //---------------------------------------------------------------------------------------------- // // Skin parts // //---------------------------------------------------------------------------------------------- [SkinPart(required="false")] /** * A skin part that can be dragged along the track. * The
thumbPosition
property contains the thumb's
* current position along the track.
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
public var thumb:IVisualElement;
[SkinPart(required="false")]
/**
* A skin part that defines the bounds along which the thumb can
* be dragged.
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
public var track:IVisualElement;
//----------------------------------------------------------------------------------------------
//
// Overridden properties
//
//----------------------------------------------------------------------------------------------
//----------------------------------
// selected
//----------------------------------
/**
* The current position of the toggle switch.
* A value of false
corresponds to the unselected position,
* and a value of 1
corresponds to the selected position.
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
override public function set selected(value:Boolean):void
{
super.selected = value;
var newValue:Number = selectedToPosition(value);
slideToPosition = newValue;
setThumbPosition(newValue);
}
//----------------------------------------------------------------------------------------------
//
// Properties
//
//----------------------------------------------------------------------------------------------
//----------------------------------
// thumbPosition
//----------------------------------
/**
* The animation between thumbPosition and slideToPosition, which
* drives the thumb's position. exposed for testing.
*/
private var _animator:Animation = null;
/**
* @private
*/
mx_internal function get animator():Animation
{
return _animator;
}
/**
* @private
* additional setup is performed on mouse events, before
* we start the animation
*/
mx_internal function set animator(value:Animation): void
{
_animator = value;
}
//----------------------------------
// thumbPosition
//----------------------------------
/**
* Storage for thumbPosition
*/
private var _thumbPosition:Number = 0.0;
[Bindable(event="thumbPositionChanged")]
/**
* The thumb's current position along the track.
* The range of value is between 0.0, unselected,
* and 1.0, selected.
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
public function get thumbPosition():Number
{
return _thumbPosition;
}
//----------------------------------------------------------------------------------------------
//
// Overridden Methods
//
//----------------------------------------------------------------------------------------------
/**
* @private
*/
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
updateSkinDisplayList();
}
/**
* @private
*/
override protected function attachSkin():void
{
super.attachSkin();
skin.addEventListener(FlexEvent.UPDATE_COMPLETE, updateCompleteHandler);
skin.addEventListener(ResizeEvent.RESIZE, resizeHandler);
}
/**
* @private
*/
override protected function addHandlers():void
{
super.addHandlers();
mouseDragUtil = new MouseDragUtil(this, mouseDownHandler,
mouseDragHandler, thinnedMouseDragHandler, mouseUpHandler);
mouseDragUtil.setupHandlers();
}
//----------------------------------------------------------------------------------------------
//
// Methods
//
//----------------------------------------------------------------------------------------------
/**
* Convert the given thumb position to a selected value
*/
private function positionToSelected(value:Number):Boolean
{
return value > 0.5;
}
/**
* Convert the selected value to a thumb position
*/
private function selectedToPosition(value:Boolean):Number
{
return value ? 1.0 : 0.0;
}
/**
* Specify the new position the toggle switch should animate to.
* At the end of the animation, selection will update.
*/
private function moveToPositionAndSelect(newPosition:Number):void
{
var slideDuration:Number = getStyle("slideDuration");
if (newPosition != thumbPosition && slideDuration > 0)
{
// Finish any current animation before we start the next one.
if (animator.isPlaying)
stopAnimation();
// holds the final value to be set when animation ends
slideToPosition = newPosition;
var duration:Number = slideDuration *
(Math.abs(thumbPosition - slideToPosition));
animateToPosition(animator, thumbPosition, newPosition, duration);
}
else
{
// we are either at the destination position,
// or we should update immediately
setSelected(positionToSelected(newPosition));
}
}
/**
* Specify the new position the toggle switch should animate to
* during mouse drag.
* Selection does not update after the animation.
*/
private function moveToPosition(newPosition:Number):void
{
if (newPosition != thumbPosition)
{
// Finish any current animation before we start the next one.
if (animator.isPlaying)
stopAnimation();
animateToPosition(animator, thumbPosition, newPosition, MouseDragUtil.MAX_UPDATE_RATE);
}
}
/**
* When the selection is changed by user interactions, fire a change event
* when appropriate.
*/
private function setSelected(value:Boolean):void
{
var valueChanged:Boolean = value != selected;
selected = value;
if (valueChanged)
dispatchEvent(new Event(Event.CHANGE));
}
/**
* Prepare the animator for use as a single animation to the edge of
* the track, or for use in a series of animations following mouse
* drag events.
*/
private function setupAnimator(animator:Animation, selectAtCompletion:Boolean):void
{
stopAnimation();
var animTarget:AnimationTargetHelper = animator.animationTarget as AnimationTargetHelper;
if (!animTarget)
animator.animationTarget = animTarget = new AnimationTargetHelper();
animTarget.updateFunction = animationUpdateHandler;
animator.motionPaths = new