blob: e0315753d7bb98ebbd4757a88ce9eaa7d7a1a93d [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.controls
{
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.text.TextLineMetrics;
import flash.utils.Timer;
import mx.core.IFlexDisplayObject;
import mx.core.IFlexModuleFactory;
import mx.core.IFontContextComponent;
import mx.core.mx_internal;
import mx.core.IUITextField;
import mx.core.UIComponent;
import mx.core.UITextField;
import mx.events.FlexEvent;
import mx.styles.ISimpleStyleClient;
use namespace mx_internal;
//--------------------------------------
// Events
//--------------------------------------
/**
* Dispatched when the load completes.
*
* @eventType flash.events.Event.COMPLETE
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="complete", type="flash.events.Event")]
/**
* Dispatched when an object's state changes from visible to invisible.
*
* @eventType mx.events.FlexEvent.HIDE
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="hide", type="mx.events.FlexEvent")]
/**
* Dispatched as content loads in event
* or polled mode.
*
* @eventType flash.events.ProgressEvent.PROGRESS
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="progress", type="flash.events.ProgressEvent")]
/**
* Dispatched when the component becomes visible.
*
* @eventType mx.events.FlexEvent.SHOW
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="show", type="mx.events.FlexEvent")]
//--------------------------------------
// Styles
//--------------------------------------
include "../styles/metadata/BarColorStyle.as"
include "../styles/metadata/GapStyles.as"
include "../styles/metadata/LeadingStyle.as"
include "../styles/metadata/PaddingStyles.as"
include "../styles/metadata/TextStyles.as"
/**
* Skin style for a determinate progress bar.
*
* The default value for the Halo theme is <code>mx.skins.halo.ProgressBarSkin</code>.
* The default value for the Spark theme is <code>mx.skins.spark.ProgressBarSkin</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="barSkin", type="Class", inherit="no")]
/**
* Black section of a three-dimensional border, or the color section
* of a two-dimensional border.
* @default 0xB7BABC
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="borderColor", type="uint", format="Color", inherit="no", theme="halo")]
/**
* The number of pixels to move the indeterminate progress bar for each indeterminate loop.
* Once the progress bar has moved the specified number of pixels, it gets respositioned back to
* its starting point. A value of 0 means that the bar is not moved.
*
* The default value for the Halo theme is <code>28</code>.
* The default value for the Spark theme is <code>14</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="indeterminateMoveInterval", type="Number", inherit="no")]
/**
* Skin style for an indeterminate progress bar.
*
* The default value for the Halo theme is <code>mx.skins.halo.ProgressIndeterminateSkin</code>.
* The default value for the Spark theme is <code>mx.skins.spark.ProgressIndeterminateSkin</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="indeterminateSkin", type="Class", inherit="no")]
/**
* Skin style for the mask of the determinate and indeterminate bars.
*
* The default value for the Halo theme is <code>mx.skins.halo.ProgressMaskSkin</code>.
* The default value for the Spark theme is <code>mx.skins.spark.ProgressMaskSkin</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="maskSkin", type="Class", inherit="no")]
/**
* Skin style for the progress indicator track.
*
* The default value for the Halo theme is <code>mx.skins.halo.ProgressTrackSkin</code>.
* The default value for the Spark theme is <code>mx.skins.spark.ProgressBarTrackSkin</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="trackSkin", type="Class", inherit="no")]
/**
* Theme color of the ProgressBar control.
* Possible values are haloGreen, haloBlue, and haloOrange.
* Adobe recommends setting the <code>themeColor</code> style
* in the <code>&lt;mx:Application&gt;</code> tag, instead of in
* individual controls.
*
* @default "haloBlue"
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="themeColor", type="uint", format="Color", inherit="yes", theme="halo")]
/**
* The colors of the track, as an array of two colors.
* You can use the same color twice for a solid track color.
*
* @default [ 0xE6EEEE, 0xE6EEEE ]
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="trackColors", type="Array", arrayType="uint", format="Color", inherit="no", theme="halo")]
/**
* The height of the track in pixels. If the value is NaN, then
* use the height of the skin specified by the <code>trackSkin</code> property.
*
* @default NaN
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="trackHeight", type="Number", format="Length", inherit="no")]
/**
* The width of the label in pixels. If the value is NaN,
* the ProgressBar control sets it to the width of the control.
*
* @default NaN
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="labelWidth", type="Number", format="Length", inherit="yes")]
//--------------------------------------
// Effects
//--------------------------------------
/**
* Effect called when Flex dispatches the <code>complete</code> event,
* which occurs when the load completes.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Effect(name="completeEffect", event="complete")]
//--------------------------------------
// Other metadata
//--------------------------------------
[DefaultBindingProperty(source="percentComplete")]
[DefaultTriggerEvent("progress")]
[IconFile("ProgressBar.png")]
[ResourceBundle("controls")]
/**
* Because this component does not define a skin for the mobile theme, Adobe
* recommends that you not use it in a mobile application. Alternatively, you
* can define your own mobile skin for the component. For more information,
* see <a href="http://help.adobe.com/en_US/flex/mobileapps/WS19f279b149e7481c698e85712b3011fe73-8000.html">Basics of mobile skinning</a>.
*/
[DiscouragedForProfile("mobileDevice")]
/**
* The ProgressBar control provides a visual representation of the progress of a task over
* time. There are two types of ProgressBar controls: determinate and indeterminate.
*
* <p>A determinate ProgressBar control is a linear representation of the progress of a task over time.
* You use a determinate ProgressBar when the scope of the task is known. It displays when the user
* has to wait for an extended amount of time.</p>
*
* <p>An indeterminate ProgressBar control represents time-based processes for which the scope is
* not yet known. As soon as you can determine the scope,
* you should use a determinate ProgressBar control.</p>
*
* <p>The ProgressBar control has the following default characteristics:</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>default size</td>
* <td>150 pixels wide by 4 pixels high</td>
* </tr>
* <tr>
* <td>Minimum size</td>
* <td>0 pixels</td>
* </tr>
* <tr>
* <td>Maximum size</td>
* <td>Undefined</td>
* </tr>
* </table>
*
* @mxml
*
* <p>The <code>&lt;mx:ProgressBar&gt;</code> tag inherits all of the tag attributes
* of its superclass, and adds the following tag attributes:</p>
*
* <pre>
* &lt;mx:ProgressBar
* <strong>Properties</strong>
* conversion="1"
* direction="right|left"
* indeterminate="false|true"
* label="<i>No default</i>"
* labelPlacement="bottom|top|left|right|center"
* maximum="0"
* minimum="0"
* mode="event|polled|manual"
* source="<i>No default</i>"
*
* <strong>Styles</strong>
* barColor="undefined"
* barSkin="ProgressBarSkin"
* borderColor="0xAAB3B3"
* color="0x0B333C"
* disabledColor="0xAAB3B3"
* fontAntiAliasType="advanced"
* fontFamily="Verdana"
* fontGridFitType="pixel"
* fontSharpness="0"
* fontSize="10"
* fontThickness="0"
* fontStyle="normal|italic"
* fontWeight="normal|bold"
* horizontalGap="8"
* indeterminateMoveInterval="26"
* indeterminateSkin="ProgressIndeterminateSkin"
* labelWidth="Computed"
* leading="0"
* maskSkin="ProgressMaskSkin"
* paddingLeft="0"
* paddingRight="0"
* textAlign="left|right|center"
* textDecoration="none|underline"
* textIndent="0"
* themeColor="haloGreen|haloBlue|haloOrange"
* trackColors="[0xE6EEEE,0xE6EEEE]"
* trackHeight="Calculated"
* trackSkin="ProgressTrackSkin"
* verticalGap="6"
*
* <strong>Events</strong>
* complete="<i>No default</i>"
* hide="<i>No default</i>"
* progress="<i>No default</i>"
* show="<i>No default</i>"
*
* <strong>Effects</strong>
* completeEffect="<i>No default</i>"
* /&gt;
* </pre>
* </p>
*
* @see mx.controls.ProgressBarDirection
* @see mx.controls.ProgressBarLabelPlacement
* @see mx.controls.ProgressBarMode
*
* @includeExample examples/SimpleProgressBar.mxml
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class ProgressBar extends UIComponent implements IFontContextComponent
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function ProgressBar()
{
super();
pollTimer = new Timer(_interval);
cacheAsBitmap = true;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
mx_internal var _content:UIComponent;
/**
* @private
*/
mx_internal var _bar:UIComponent;
/**
* @private
*/
mx_internal var _indeterminateBar:IFlexDisplayObject;
/**
* @private
*/
mx_internal var _determinateBar:IFlexDisplayObject;
/**
* @private
*/
mx_internal var _track:IFlexDisplayObject;
/**
* @private
*/
mx_internal var _barMask:IFlexDisplayObject;
/**
* @private
*/
mx_internal var _labelField:IUITextField;
/**
* @private
*/
private var pollTimer:Timer;
/**
* @private
*/
private var _interval:Number = 30;
/**
* @private
*/
private var indeterminatePlaying:Boolean = false;
/**
* @private
*/
private var stopPolledMode:Boolean = false;
/**
* @private
*/
private var barSkinChanged:Boolean = false;
/**
* @private
*/
private var trackSkinChanged:Boolean = false;
/**
* @private
*/
private var indeterminateSkinChanged:Boolean = false;
/**
* @private
*/
private var visibleChanged:Boolean = false;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// conversion
//----------------------------------
/**
* @private
* Storage for the conversion property.
*/
private var _conversion:Number = 1;
[Bindable("conversionChanged")]
[Inspectable(defaultValue="1")]
/**
* Number used to convert incoming current bytes loaded value and
* the total bytes loaded values.
* Flex divides the current and total values by this property and
* uses the closest integer that is less than or equal to each
* value in the label string. A value of 1 does no conversion.
*
* @default 1
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get conversion():Number
{
return _conversion;
}
/**
* @private
*/
public function set conversion(value:Number):void
{
if (!isNaN(value) && Number(value) > 0 && value != _conversion)
{
_conversion = Number(value);
invalidateDisplayList();
dispatchEvent(new Event("conversionChanged"));
}
}
//----------------------------------
// direction
//----------------------------------
/**
* @private
* Storage for the direction property.
*/
private var _direction:String = ProgressBarDirection.RIGHT;
[Bindable("directionChanged")]
[Inspectable(enumeration="left,right", defaultValue="right")]
/**
* Direction in which the fill of the ProgressBar expands toward completion.
* Valid values in MXML are
* <code>"right"</code> and <code>"left"</code>.
*
* <p>In ActionScript, you use use the following constants
* to set this property:
* <code>ProgressBarDirection.RIGHT</code> and
* <code>ProgressBarDirection.LEFT</code>.</p>
*
* @see mx.controls.ProgressBarDirection
* @default ProgressBarDirection.RIGHT
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get direction():String
{
return _direction;
}
/**
* @private
*/
public function set direction(value:String):void
{
if (value == ProgressBarDirection.LEFT || value == ProgressBarDirection.RIGHT)
_direction = value;
invalidateDisplayList();
dispatchEvent(new Event("directionChanged"));
}
//----------------------------------
// fontContext
//----------------------------------
/**
* @private
*/
public function get fontContext():IFlexModuleFactory
{
return moduleFactory;
}
/**
* @private
*/
public function set fontContext(moduleFactory:IFlexModuleFactory):void
{
this.moduleFactory = moduleFactory;
}
//----------------------------------
// indeterminate
//----------------------------------
/**
* @private
* Storage for the indeterminate property.
*/
private var _indeterminate:Boolean = false;
/**
* @private
*/
private var indeterminateChanged:Boolean = true;
[Bindable("indeterminateChanged")]
[Inspectable(category="General", defaultValue="false")]
/**
* Whether the ProgressBar control has a determinate or
* indeterminate appearance.
* Use an indeterminate appearance when the progress status cannot be determined.
* If <code>true</code>, the appearance is indeterminate.
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get indeterminate():Boolean
{
return _indeterminate;
}
/**
* @private
*/
public function set indeterminate(value:Boolean):void
{
_indeterminate = value;
indeterminateChanged = true;
invalidateProperties();
invalidateDisplayList();
dispatchEvent(new Event("indeterminateChanged"));
}
//----------------------------------
// label
//----------------------------------
/**
* @private
* Storage for the label property.
*/
private var _label:String;
/**
* @private
*/
private var labelOverride:String;
[Bindable("labelChanged")]
[Inspectable(category="General", defaultValue="null")]
/**
* Text that accompanies the progress bar. You can include
* the following special characters in the text string:
*
* <ul>
* <li>%1 = current loaded bytes</li>
* <li>%2 = total bytes</li>
* <li>%3 = percent loaded</li>
* <li>%% = "%" character</li>
* </ul>
*
* <p>If a field is unknown, it is replaced by "??".
* If undefined, the label is not displayed.</p>
*
* <p>If you are in manual mode, you can set the values of these special characters
* by using the <code>setProgress()</code> method.</p>
*
* @default "LOADING %3%%"
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get label():String
{
return _label;
}
/**
* @private
*/
public function set label(value:String):void
{
labelOverride = value;
_label = value != null ?
value :
resourceManager.getString(
"controls", "label");
invalidateDisplayList();
dispatchEvent(new Event("labelChanged"));
}
//----------------------------------
// labelPlacement
//----------------------------------
/**
* @private
* Storage for the labelPlacement property.
*/
private var _labelPlacement:String = ProgressBarLabelPlacement.BOTTOM;
[Bindable("labelPlacementChanged")]
[Inspectable(category="General", enumeration="left,right,top,bottom,center", defaultValue="bottom")]
/**
* Placement of the label.
* Valid values in MXML are <code>"right"</code>, <code>"left"</code>,
* <code>"bottom"</code>, <code>"center"</code>, and <code>"top"</code>.
*
* <p>In ActionScript, you can use use the following constants to set this property:
* <code>ProgressBarLabelPlacement.RIGHT</code>, <code>ProgressBarLabelPlacement.LEFT</code>,
* <code>ProgressBarLabelPlacement.BOTTOM</code>, <code>ProgressBarLabelPlacement.CENTER</code>,
* and <code>ProgressBarLabelPlacement.TOP</code>.</p>
*
* @see mx.controls.ProgressBarLabelPlacement
* @default ProgressBarLabelPlacement.BOTTOM
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get labelPlacement():String
{
return _labelPlacement;
}
/**
* @private
*/
public function set labelPlacement(value:String):void
{
if (value != _labelPlacement)
_labelPlacement = value;
invalidateSize();
invalidateDisplayList();
dispatchEvent(new Event("labelPlacementChanged"));
}
//----------------------------------
// maximum
//----------------------------------
/**
* @private
* Storage for the maximum property.
*/
private var _maximum:Number = 0;
[Bindable("maximumChanged")]
[Inspectable(category="General", defaultValue="0")]
/**
* Largest progress value for the ProgressBar. You
* can only use this property in manual mode.
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get maximum():Number
{
return _maximum;
}
/**
* @private
*/
public function set maximum(value:Number):void
{
if (!isNaN(value) && _mode == ProgressBarMode.MANUAL && value != _maximum)
{
_maximum = value;
invalidateDisplayList();
dispatchEvent(new Event("maximumChanged"));
}
}
//----------------------------------
// minimum
//----------------------------------
/**
* @private
* Storage for the minimum property.
*/
private var _minimum:Number = 0;
[Bindable("minimumChanged")]
[Inspectable(category="General", defaultValue="0")]
/**
* Smallest progress value for the ProgressBar. This
* property is set by the developer only in manual mode.
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get minimum():Number
{
return _minimum;
}
/**
* @private
*/
public function set minimum(value:Number):void
{
if (!isNaN(value) && _mode == ProgressBarMode.MANUAL && value != _minimum)
{
_minimum = value;
invalidateDisplayList();
dispatchEvent(new Event("minimumChanged"));
}
}
//----------------------------------
// mode
//----------------------------------
/**
* @private
* Storage for the mode property.
*/
private var _mode:String = ProgressBarMode.EVENT;
/**
* @private
*/
private var modeChanged:Boolean = false;
[Bindable("modeChanged")]
[Inspectable(category="General", enumeration="event,polled,manual", defaultValue="event")]
/**
* Specifies the method used to update the bar.
* Use one of the following values in MXML:
*
* <ul>
* <li><code>event</code> The control specified by the <code>source</code>
* property must dispatch progress and completed events.
* The ProgressBar control uses these events to update its status.
* The ProgressBar control only updates if the value of
* the <code>source</code> property extends the EventDispatcher class.</li>
*
* <li><code>polled</code> The <code>source</code> property must specify
* an object that exposes <code>bytesLoaded</code> and
* <code>bytesTotal</code> properties. The ProgressBar control
* calls these methods to update its status.</li>
*
* <li><code>manual</code> You manually update the ProgressBar status.
* In this mode you specify the <code>maximum</code> and <code>minimum</code>
* properties and use the <code>setProgress()</code> property method to
* specify the status. This mode is often used when the <code>indeterminate</code>
* property is <code>true</code>.</li>
* </ul>
*
* <p>In ActionScript, you can use use the following constants to set this property:
* <code>ProgressBarMode.EVENT</code>, <code>ProgressBarMode.POLLED</code>,
* and <code>ProgressBarMode.MANUAL</code>.</p>
*
* @see mx.controls.ProgressBarMode
*
* @default ProgressBarMode.EVENT
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get mode():String
{
return _mode;
}
/**
* @private
*/
public function set mode(value:String):void
{
if (value != _mode)
{
if (_mode == ProgressBarMode.POLLED)
stopPolledMode = true;
_mode = value;
modeChanged = true;
indeterminateChanged = true;
invalidateProperties();
invalidateDisplayList();
}
}
//----------------------------------
// percentComplete
//----------------------------------
[Bindable("progress")]
/**
* Percentage of process that is completed.The range is 0 to 100.
* Use the <code>setProgress()</code> method to change the percentage.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get percentComplete():Number
{
if (_value < _minimum || _maximum < _minimum)
return 0;
// Avoid divide by zero fault.
if ((_maximum - _minimum) == 0)
return 0;
var perc:Number = 100 * (_value - _minimum) / (_maximum - _minimum);
if (isNaN(perc) || perc < 0)
return 0;
else if (perc > 100)
return 100;
else
return perc;
}
//----------------------------------
// source
//----------------------------------
/**
* @private
* Storage for the source property.
*/
private var _source:Object;
/**
* @private
*/
private var _stringSource:String;
/**
* @private
*/
private var sourceChanged:Boolean = false;
/**
* @private
*/
private var stringSourceChanged:Boolean = false;
[Bindable("sourceChanged")]
[Inspectable(category="General")]
/**
* Refers to the control that the ProgressBar is measuring the progress of. Use this property only in
* event and polled mode. A typical usage is to set this property to a Loader control.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get source():Object
{
return _source;
}
/**
* @private
*/
public function set source(value:Object):void
{
if (value is String)
{
_stringSource = String(value);
try
{
value = document[_stringSource];
}
catch(e:Error)
{
stringSourceChanged = true; // Try again in commitProperties
}
}
if (_source && _source is IEventDispatcher)
removeSourceListeners();
if (value)
{
_source = value;
sourceChanged = true;
modeChanged = true;
indeterminateChanged = true;
invalidateProperties();
invalidateDisplayList();
}
else if (_source != null)
{
_source = null;
sourceChanged = true;
indeterminateChanged = true;
invalidateProperties();
invalidateDisplayList();
pollTimer.reset();
}
}
//----------------------------------
// value
//----------------------------------
/**
* @private
* Storage for the value property.
*/
private var _value:Number = 0;
[Bindable("change")]
/**
* Read-only property that contains the amount of progress
* that has been made - between the minimum and maximum values.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get value():Number
{
return _value;
}
//--------------------------------------------------------------------------
//
// Overridden properties
//
//--------------------------------------------------------------------------
/**
* @private
*/
override public function set visible(value:Boolean):void
{
super.visible = value;
visibleChanged = true;
invalidateDisplayList();
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function createChildren():void
{
super.createChildren();
if (!_content)
{
_content = new UIComponent();
addChild(_content);
}
if (!_bar)
{
_bar = new UIComponent();
_content.addChild(_bar);
}
if (!_barMask)
{
var barMaskClass:Class = getStyle("maskSkin");
_barMask = new barMaskClass();
_barMask.visible = true;
_bar.addChild(DisplayObject(_barMask));
UIComponent(_bar).mask = DisplayObject(_barMask);
}
if (!_labelField)
{
_labelField = IUITextField(createInFontContext(UITextField));
_labelField.styleName = this;
addChild(DisplayObject(_labelField));
}
}
/**
* @private
*/
override protected function childrenCreated():void
{
super.childrenCreated();
// Mark all of our skins as changed so they will get created.
trackSkinChanged = true;
barSkinChanged = true;
indeterminateSkinChanged = true;
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void
{
var invalidate:Boolean = false;
super.styleChanged(styleProp);
if (styleProp == null || styleProp == "styleName")
{
// Wholesale change, need to update all skins
barSkinChanged = trackSkinChanged = indeterminateSkinChanged = true;
invalidate = true;
}
else if (styleProp == "barSkin")
{
barSkinChanged = true;
invalidate = true;
}
else if (styleProp == "trackSkin")
{
trackSkinChanged = true;
invalidate = true;
}
else if (styleProp == "indeterminateSkin")
{
indeterminateSkinChanged = true;
invalidate = true;
}
if (invalidate)
{
invalidateProperties();
invalidateSize();
invalidateDisplayList();
}
}
/**
* @private
*/
override protected function commitProperties():void
{
super.commitProperties();
// if the font changed and we already created the label, we will need to
// destory it so it can be re-created, possibly in a different swf context.
if (hasFontContextChanged() && _labelField != null)
{
var index:int = getChildIndex(DisplayObject(_labelField));
removeChild(DisplayObject(_labelField));
_labelField = IUITextField(createInFontContext(UITextField));
_labelField.styleName = this;
addChildAt(DisplayObject(_labelField), index);
}
if (trackSkinChanged)
{
trackSkinChanged = false;
createTrack();
}
if (barSkinChanged)
{
barSkinChanged = false;
createBar();
}
if (indeterminateSkinChanged)
{
indeterminateSkinChanged = false;
createIndeterminateBar();
}
if (stringSourceChanged)
{
stringSourceChanged = false;
try
{
_source = document[_stringSource];
}
catch(e:Error)
{
// If we fail here, then the source refers to an object that doesn't exist
// on the document
}
}
if (sourceChanged)
{
sourceChanged = false;
dispatchEvent(new Event("sourceChanged"));
}
if (modeChanged)
{
modeChanged = false;
if (_source)
{
if (_mode == ProgressBarMode.EVENT)
{
if (_source is IEventDispatcher)
{
addSourceListeners();
}
else
{
// the Loader object is not yet initialized properly,
// as it is put on stage after the progressbar
// so make it go thru the source re-setting in draw
_source = null;
}
}
else if (_source is IEventDispatcher)
{
removeSourceListeners();
}
}
if (_mode == ProgressBarMode.POLLED)
{
// weak listener in case the pbar is removed before the timer is reset()
// safe because pollTimer lives in the pbar
pollTimer.addEventListener(TimerEvent.TIMER, updatePolledHandler, false, 0, true);
pollTimer.start();
}
else if (stopPolledMode)
{
stopPolledMode = false;
pollTimer.removeEventListener(TimerEvent.TIMER, updatePolledHandler);
pollTimer.reset();
}
dispatchEvent(new Event("modeChanged"));
}
}
/**
* @private
*/
override protected function measure():void
{
super.measure();
var prefWidth:Number;
var prefHeight:Number;
var minWidth:Number = NaN;
var minHeight:Number = NaN;
var trackHeight:Number = getStyle("trackHeight");
var preferredTrackWidth:Number = _track.measuredWidth;
var preferredTrackHeight:Number = isNaN(trackHeight) ?
_track.measuredHeight:
trackHeight;
var horizontalGap:Number = getStyle("horizontalGap");
var verticalGap:Number = getStyle("verticalGap");
var paddingLeft:Number = getStyle("paddingLeft");
var paddingRight:Number = getStyle("paddingRight");
var paddingTop:Number = getStyle("paddingTop");
var paddingBottom:Number = getStyle("paddingBottom");
var labelWidth:Number = getStyle("labelWidth");
var lineMetrics:TextLineMetrics = measureText(predictLabelText());
var textWidth:Number = isNaN(labelWidth) ?
lineMetrics.width + UITextField.TEXT_WIDTH_PADDING :
labelWidth;
var textHeight:Number = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
switch (labelPlacement)
{
case ProgressBarLabelPlacement.LEFT:
case ProgressBarLabelPlacement.RIGHT:
{
prefWidth = textWidth + preferredTrackWidth +
paddingLeft + paddingRight + horizontalGap;
prefHeight = Math.max(textHeight,preferredTrackHeight) +
paddingTop + paddingBottom;
measuredMinWidth = prefWidth;
break;
}
case ProgressBarLabelPlacement.CENTER:
{
prefWidth = Math.max(textWidth, preferredTrackWidth) +
paddingLeft + paddingRight + horizontalGap;
prefHeight = Math.max(textHeight,preferredTrackHeight) +
paddingTop + paddingBottom;
measuredMinWidth = textWidth;
break;
}
default: /* ProgressBarLabelPlacement.TOP && ProgressBarLabelPlacement.BOTTOM */
{
prefWidth = Math.max(textWidth, preferredTrackWidth) +
paddingLeft + paddingRight;
prefHeight = textHeight + preferredTrackHeight +
paddingTop + paddingBottom + verticalGap;
measuredMinWidth = textWidth;
break;
}
}
measuredWidth = prefWidth;
measuredMinHeight = measuredHeight = prefHeight;
if (!isNaN(minWidth))
measuredMinWidth = minWidth;
if (!isNaN(minHeight))
measuredMinHeight = minHeight;
}
/**
* @private
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
var horizontalGap:Number = getStyle("horizontalGap");
var verticalGap:Number = getStyle("verticalGap");
var paddingLeft:Number = getStyle("paddingLeft");
var paddingRight:Number = getStyle("paddingRight");
var paddingTop:Number = getStyle("paddingTop");
var paddingBottom:Number = getStyle("paddingBottom");
var left:Number = paddingLeft;
var top:Number = paddingTop;
var labelWidth:Number = getStyle("labelWidth");
var trackHeight:Number = getStyle("trackHeight");
trackHeight = isNaN(trackHeight) ?
_track.measuredHeight :
trackHeight;
var lineMetrics:TextLineMetrics = measureText(predictLabelText());
var textWidth:Number = isNaN(labelWidth) ?
lineMetrics.width + UITextField.TEXT_WIDTH_PADDING :
labelWidth;
var textHeight:Number = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
switch (labelPlacement)
{
case ProgressBarLabelPlacement.TOP:
{
_labelField.move(left,top);
_labelField.setActualSize(textWidth, textHeight);
_content.move(left, top + textHeight + verticalGap);
layoutContent(unscaledWidth - left - paddingRight, trackHeight);
break;
}
case ProgressBarLabelPlacement.RIGHT:
{
var cWidth:Number = unscaledWidth - left -
paddingRight - textWidth - horizontalGap;
_labelField.move(left + cWidth + horizontalGap,
(unscaledHeight - textHeight) / 2);
_labelField.setActualSize(textWidth, textHeight);
_content.move(left,top + (textHeight - trackHeight) / 2);
layoutContent(cWidth, trackHeight);
break;
}
case ProgressBarLabelPlacement.LEFT:
{
_labelField.move(left, top + (unscaledHeight - textHeight) / 2);
_labelField.setActualSize(textWidth, textHeight);
_content.move(left + textWidth + horizontalGap,
top + (textHeight - trackHeight) / 2);
layoutContent(unscaledWidth - left - textWidth -
verticalGap - paddingRight, trackHeight);
break;
}
case ProgressBarLabelPlacement.CENTER:
{
_labelField.move((unscaledWidth - textWidth) / 2,
(unscaledHeight - textHeight) / 2);
_labelField.setActualSize(textWidth, textHeight);
_content.move(left,top);
layoutContent(unscaledWidth - paddingRight,
unscaledHeight - paddingBottom);
break;
}
default: /* case ProgressBarLabelPlacement.BOTTOM */
{
_labelField.move(left,top + trackHeight + verticalGap);
_labelField.setActualSize(textWidth, textHeight);
_content.move(left, top);
layoutContent(unscaledWidth - left - paddingRight, trackHeight);
break;
}
}
//layout mask
if (_barMask)
{
_barMask.move(0,0);
_barMask.setActualSize(_track.width, _track.height);
}
// Print position/sizes of children
//trace("_labelField x",_labelField.x,"y",_labelField.y,"w",_labelField.width,"h",_labelField.height);
//trace("_content x",_content.x,"y",_content.y,"w",_content.width,"h",_content.height);
_labelField.text = getFullLabelText();
// TODO: redundant? the IF below does this
_indeterminateBar.visible = _indeterminate;
if (indeterminateChanged || visibleChanged)
{
indeterminateChanged = false;
visibleChanged = false;
_indeterminateBar.visible = _indeterminate;
if (_indeterminate && _source == null && _mode == ProgressBarMode.EVENT && visible)
startPlayingIndeterminate();
else
stopPlayingIndeterminate();
}
if (_indeterminate)
{
_determinateBar.setActualSize(_track.width, _track.height);
}
else
{
var w:Number = Math.max(0, _track.width * percentComplete / 100);
_determinateBar.setActualSize(w, _track.height);
_determinateBar.x = direction == ProgressBarDirection.RIGHT ?
0 :
_track.width - w;
}
}
/**
* @private
*/
override protected function resourcesChanged():void
{
super.resourcesChanged();
label = labelOverride;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Sets the state of the bar to reflect the amount of progress made
* when using manual mode.
* The <code>value</code> argument is assigned to the <code>value</code>
* property and the <code>maximum</code> argument is assigned to the
* <code>maximum</code> property.
* The <code>minimum</code> property is not altered.
*
* @param value Current value.
*
* @param maximum Total or target value.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function setProgress(value:Number, total:Number):void
{
if (_mode == ProgressBarMode.MANUAL)
_setProgress(value, total);
}
/**
* @private
* Changes the value and the maximum properties.
*/
private function _setProgress(value:Number, maximum:Number):void
{
if (enabled && !isNaN(value) && !isNaN(maximum))
{
_value = value;
_maximum = maximum;
// Dipatch an Event of type "change".
dispatchEvent(new Event(Event.CHANGE));
// Dispatch a Progress
var progressEvent:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS);
progressEvent.bytesLoaded = value;
progressEvent.bytesTotal = maximum;
dispatchEvent(progressEvent);
if (_indeterminate)
startPlayingIndeterminate();
if (_value == _maximum && _value > 0)
{
if (_indeterminate)
stopPlayingIndeterminate();
if (mode != ProgressBarMode.EVENT) // We get our own complete event when in event mode
dispatchEvent(new Event(Event.COMPLETE));
}
invalidateDisplayList();
}
}
/**
* @private
*/
private function createTrack():void
{
if (_track)
{
_content.removeChild(DisplayObject(_track));
_track = null;
}
// Create the track frame
var trackClass:Class = getStyle('trackSkin');
if (trackClass)
{
_track = new trackClass();
if (_track is ISimpleStyleClient)
ISimpleStyleClient(_track).styleName = this;
_content.addChildAt(DisplayObject(_track), 0);
}
}
/**
* @private
*/
private function createBar():void
{
if (_determinateBar)
{
_bar.removeChild(DisplayObject(_determinateBar));
_determinateBar = null;
}
// Create the determinate bar
var barClass:Class = getStyle('barSkin');
if (barClass)
{
_determinateBar = new barClass();
if (_determinateBar is ISimpleStyleClient)
ISimpleStyleClient(_determinateBar).styleName = this;
_bar.addChild(DisplayObject(_determinateBar));
}
}
/**
* @private
*/
private function createIndeterminateBar():void
{
if (_indeterminateBar)
{
_bar.removeChild(DisplayObject(_indeterminateBar));
_indeterminateBar = null;
}
// Create the indeterminate bar
var indeterminateClass:Class = getStyle('indeterminateSkin');
if (indeterminateClass)
{
_indeterminateBar = new indeterminateClass();
if (_indeterminateBar is ISimpleStyleClient)
ISimpleStyleClient(_indeterminateBar).styleName = this;
_indeterminateBar.visible = false;
_bar.addChild(DisplayObject(_indeterminateBar));
}
}
/**
* @private
*/
private function layoutContent(newWidth:Number, newHeight:Number):void
{
_track.move(0, 0);
_track.setActualSize(newWidth, newHeight);
_bar.move(0, 0);
_determinateBar.move(0, 0);
_indeterminateBar.setActualSize(newWidth + getStyle("indeterminateMoveInterval"), newHeight);
}
/**
* @private
*/
private function getFullLabelText():String
{
var current:Number = Math.max(_value /* - _minimum */,0);
var total:Number = Math.max(_maximum /* - _minimum */,0);
var labelText:String = label;
if (labelText)
{
if (_indeterminate)
{
labelText = labelText.replace("%1", String(Math.floor(current / _conversion)));
labelText = labelText.replace("%2", "??");
labelText = labelText.replace("%3", "");
labelText = labelText.replace("%%", "");
}
else
{
labelText = labelText.replace("%1", String(Math.floor(current / _conversion)));
labelText = labelText.replace("%2", String(Math.floor(total / _conversion)));
labelText = labelText.replace("%3", String(Math.floor(percentComplete)));
labelText = labelText.replace("%%", "%");
}
}
return labelText;
}
/**
* @private
* Make a good guess at the largest size of the label based on which placeholders are present
*/
private function predictLabelText():String
{
// The label will be null if there are no resources.
if (label == null)
return "";
var labelText:String = label;
var largestValue:Number;
if (_maximum != 0)
largestValue = _maximum;
else
largestValue = 100000;
if (labelText)
{
if (_indeterminate)
{
labelText = labelText.replace("%1", String(Math.floor(largestValue / _conversion)));
labelText = labelText.replace("%2", "??");
labelText = labelText.replace("%3", "");
labelText = labelText.replace("%%", "");
}
else
{
labelText = labelText.replace("%1", String(Math.floor(largestValue / _conversion)));
labelText = labelText.replace("%2", String(Math.floor(largestValue / _conversion)));
labelText = labelText.replace("%3", "100");
labelText = labelText.replace("%%", "%");
}
}
var actualText:String = getFullLabelText();
// Return the longer of the two strings
if (labelText.length > actualText.length)
return labelText;
else
return actualText;
}
/**
* @private
*/
private function startPlayingIndeterminate():void
{
if (!indeterminatePlaying)
{
indeterminatePlaying = true;
// weak listener in case the pbar is removed before the timer is reset()
// safe because pollTimer lives in the pbar
pollTimer.addEventListener(TimerEvent.TIMER, updateIndeterminateHandler, false, 0, true);
pollTimer.start();
}
}
/**
* @private
*/
private function stopPlayingIndeterminate():void
{
if (indeterminatePlaying)
{
indeterminatePlaying = false;
pollTimer.removeEventListener(TimerEvent.TIMER, updateIndeterminateHandler);
if (_mode != ProgressBarMode.POLLED)
pollTimer.reset();
}
}
/**
* @private
*/
private function addSourceListeners():void
{
_source.addEventListener(ProgressEvent.PROGRESS, progressHandler);
_source.addEventListener(Event.COMPLETE, completeHandler);
}
/**
* @private
*/
private function removeSourceListeners():void
{
_source.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
_source.removeEventListener(Event.COMPLETE, completeHandler);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
* "progress" event handler for event mode
*/
private function progressHandler(event:ProgressEvent):void
{
_setProgress(event.bytesLoaded, event.bytesTotal);
}
/**
* @private
* "complete" event handler for event mode
*/
private function completeHandler(event:Event):void
{
dispatchEvent(event);
invalidateDisplayList();
}
/**
* @private
*/
private function updateIndeterminateHandler(event:Event):void
{
if (_indeterminateBar.x < 1)
_indeterminateBar.x += 1;
else
_indeterminateBar.x = - (getStyle("indeterminateMoveInterval") - 2);
}
/**
* @private
* Callback method for polled mode.
*/
private function updatePolledHandler(event:Event):void
{
if (_source)
{
var comp:Object = _source;
var bytesLoaded:Number = comp.bytesLoaded;
var bytesTotal:Number = comp.bytesTotal;
if (!isNaN(bytesLoaded) && !isNaN(bytesTotal))
{
_setProgress(bytesLoaded, bytesTotal);
// 0 is the size of an empty movie clip??
if (percentComplete >= 100 && _value > 0)
pollTimer.reset();
}
}
}
}
}