scaffold.libs_as.feathers.controls.Button.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.IFocusDisplayObject;
import feathers.core.IStateObserver;
import feathers.core.ITextBaselineControl;
import feathers.core.ITextRenderer;
import feathers.core.IValidating;
import feathers.core.PropertyProxy;
import feathers.events.FeathersEventType;
import feathers.layout.HorizontalAlign;
import feathers.layout.RelativePosition;
import feathers.layout.VerticalAlign;
import feathers.skins.IStyleProvider;
import feathers.utils.keyboard.KeyToTrigger;
import feathers.utils.touch.LongPress;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.ui.Keyboard;
import starling.display.DisplayObject;
import starling.events.Event;
import starling.events.KeyboardEvent;
import starling.rendering.Painter;
/**
* Dispatched when the button is pressed for a long time. The property
* isLongPressEnabled
must be set to true
before
* this event will be dispatched.
*
* The following example enables long presses:
*
*
* button.isLongPressEnabled = true;
* button.addEventListener( FeathersEventType.LONG_PRESS, function( event:Event ):void
* {
* // long press
* });
*
* The properties of the event object have the following values:
*
* Property Value
* bubbles
false
* currentTarget
The 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
.
* data
null
* target
The 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.LONG_PRESS
* @see #isLongPressEnabled
* @see #longPressDuration
*/
[Event(name="longPress",type="starling.events.Event")]
/**
* A push button control that may be triggered when pressed and released.
*
* The following example creates a button, gives it a label and listens
* for when the button is triggered:
*
*
* var button:Button = new Button();
* button.label = "Click Me";
* button.addEventListener( Event.TRIGGERED, button_triggeredHandler );
* this.addChild( button );
*
* @see ../../../help/button.html How to use the Feathers Button component
*/
public class Button extends BasicButton implements IFocusDisplayObject, ITextBaselineControl
{
/**
* @private
*/
private static const HELPER_POINT:Point = new Point();
/**
* The default value added to the styleNameList
of the label.
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const DEFAULT_CHILD_STYLE_NAME_LABEL:String = "feathers-button-label";
/**
* An alternate style name to use with Button
to allow a
* theme to give it a more prominent, "call-to-action" style. If a theme
* does not provide a style for a call-to-action button, the theme will
* automatically fall back to using the default button style.
*
* An alternate style name should always be added to a component's
* styleNameList
before the component is initialized. If
* the style name is added later, it will be ignored.
*
* In the following example, the call-to-action style is applied to
* a button:
*
*
* var button:Button = new Button();
* button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON );
* this.addChild( button );
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const ALTERNATE_STYLE_NAME_CALL_TO_ACTION_BUTTON:String = "feathers-call-to-action-button";
/**
* An alternate style name to use with Button
to allow a
* theme to give it a less prominent, "quiet" style. If a theme does not
* provide a style for a quiet button, the theme will automatically fall
* back to using the default button style.
*
* An alternate style name should always be added to a component's
* styleNameList
before the component is initialized. If
* the style name is added later, it will be ignored.
*
* In the following example, the quiet button style is applied to
* a button:
*
*
* var button:Button = new Button();
* button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_QUIET_BUTTON );
* this.addChild( button );
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const ALTERNATE_STYLE_NAME_QUIET_BUTTON:String = "feathers-quiet-button";
/**
* An alternate style name to use with Button
to allow a
* theme to give it a highly prominent, "danger" style. An example would
* be a delete button or some other button that has a destructive action
* that cannot be undone if the button is triggered. If a theme does not
* provide a style for the danger button, the theme will automatically
* fall back to using the default button style.
*
* An alternate style name should always be added to a component's
* styleNameList
before the component is initialized. If
* the style name is added later, it will be ignored.
*
* In the following example, the danger button style is applied to
* a button:
*
*
* var button:Button = new Button();
* button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_DANGER_BUTTON );
* this.addChild( button );
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const ALTERNATE_STYLE_NAME_DANGER_BUTTON:String = "feathers-danger-button";
/**
* An alternate style name to use with Button
to allow a
* theme to give it a "back button" style, perhaps with an arrow
* pointing backward. If a theme does not provide a style for a back
* button, the theme will automatically fall back to using the default
* button skin.
*
* An alternate style name should always be added to a component's
* styleNameList
before the component is initialized. If
* the style name is added later, it will be ignored.
*
* In the following example, the back button style is applied to
* a button:
*
*
* var button:Button = new Button();
* button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_BACK_BUTTON );
* this.addChild( button );
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const ALTERNATE_STYLE_NAME_BACK_BUTTON:String = "feathers-back-button";
/**
* An alternate style name to use with Button
to allow a
* theme to give it a "forward" button style, perhaps with an arrow
* pointing forward. If a theme does not provide a style for a forward
* button, the theme will automatically fall back to using the default
* button style.
*
* An alternate style name should always be added to a component's
* styleNameList
before the component is initialized. If
* the style name is added later, it will be ignored.
*
* In the following example, the forward button style is applied to
* a button:
*
*
* var button:Button = new Button();
* button.styleNameList.add( Button.ALTERNATE_STYLE_NAME_FORWARD_BUTTON );
* this.addChild( button );
*
* @see feathers.core.FeathersControl#styleNameList
*/
public static const ALTERNATE_STYLE_NAME_FORWARD_BUTTON:String = "feathers-forward-button";
/**
* @private
* DEPRECATED: Replaced by feathers.controls.ButtonState.UP
.
*
* 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 STATE_UP:String = "up";
/**
* @private
* DEPRECATED: Replaced by feathers.controls.ButtonState.DOWN
.
*
* 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 STATE_DOWN:String = "down";
/**
* @private
* DEPRECATED: Replaced by feathers.controls.ButtonState.HOVER
.
*
* 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 STATE_HOVER:String = "hover";
/**
* @private
* DEPRECATED: Replaced by feathers.controls.ButtonState.DISABLED
.
*
* 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 STATE_DISABLED:String = "disabled";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.TOP
.
*
* 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 ICON_POSITION_TOP:String = "top";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.RIGHT
.
*
* 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 ICON_POSITION_RIGHT:String = "right";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.BOTTOM
.
*
* 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 ICON_POSITION_BOTTOM:String = "bottom";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.LEFT
.
*
* 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 ICON_POSITION_LEFT:String = "left";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.MANUAL
.
*
* 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 ICON_POSITION_MANUAL:String = "manual";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.LEFT_BASELINE
.
*
* 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 ICON_POSITION_LEFT_BASELINE:String = "leftBaseline";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.RelativePosition.RIGHT_BASELINE
.
*
* 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 ICON_POSITION_RIGHT_BASELINE:String = "rightBaseline";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.HorizontalAlign.LEFT
.
*
* 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 HORIZONTAL_ALIGN_LEFT:String = "left";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.HorizontalAlign.CENTER
.
*
* 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 HORIZONTAL_ALIGN_CENTER:String = "center";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.HorizontalAlign.RIGHT
.
*
* 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 HORIZONTAL_ALIGN_RIGHT:String = "right";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.VerticalAlign.TOP
.
*
* 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 VERTICAL_ALIGN_TOP:String = "top";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.VerticalAlign.MIDDLE
.
*
* 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 VERTICAL_ALIGN_MIDDLE:String = "middle";
/**
* @private
* DEPRECATED: Replaced by feathers.layout.VerticalAlign.BOTTOM
.
*
* 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 VERTICAL_ALIGN_BOTTOM:String = "bottom";
/**
* The default IStyleProvider
for all Button
* components.
*
* @default null
* @see feathers.core.FeathersControl#styleProvider
*/
public static var globalStyleProvider:IStyleProvider;
/**
* Constructor.
*/
public function Button()
{
super();
}
/**
* The value added to the styleNameList
of the label text
* renderer. This variable is protected
so that sub-classes
* can customize the label text renderer style name in their
* constructors instead of using the default style name defined by
* DEFAULT_CHILD_STYLE_NAME_LABEL
.
*
* @see feathers.core.FeathersControl#styleNameList
*/
protected var labelStyleName:String = DEFAULT_CHILD_STYLE_NAME_LABEL;
/**
* The text renderer for the button's label.
*
* For internal use in subclasses.
*
* @see #label
* @see #labelFactory
* @see #createLabel()
*/
protected var labelTextRenderer:ITextRenderer;
/**
* The currently visible icon. The value will be null
if
* there is no currently visible icon.
*
* For internal use in subclasses.
*/
protected var currentIcon:DisplayObject;
/**
* @private
*/
override protected function get defaultStyleProvider():IStyleProvider
{
return Button.globalStyleProvider;
}
/**
* @private
*/
protected var keyToTrigger:KeyToTrigger;
/**
* @private
*/
protected var longPress:LongPress;
/**
* @private
*/
protected var _scaleMatrix:Matrix;
/**
* @private
*/
protected var _label:String = null;
/**
* The text displayed on the button.
*
* The following example gives the button some label text:
*
*
* button.label = "Click Me";
*
* @default null
*/
public function get label():String
{
return this._label;
}
/**
* @private
*/
public function set label(value:String):void
{
if(this._label == value)
{
return;
}
this._label = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
protected var _hasLabelTextRenderer:Boolean = true;
/**
* Determines if the button's label text renderer is created or not.
* Useful for button sub-components that may not display text, like
* slider thumbs and tracks, or similar sub-components on scroll bars.
*
* The following example removed the label text renderer:
*
*
* button.hasLabelTextRenderer = false;
*
* @default true
*/
public function get hasLabelTextRenderer():Boolean
{
return this._hasLabelTextRenderer;
}
/**
* @private
*/
public function set hasLabelTextRenderer(value:Boolean):void
{
if(this._hasLabelTextRenderer == value)
{
return;
}
this._hasLabelTextRenderer = value;
this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER);
}
/**
* @private
*/
protected var _iconPosition:String = RelativePosition.LEFT;
[Inspectable(type="String",enumeration="top,right,bottom,left,rightBaseline,leftBaseline,manual")]
/**
* The location of the icon, relative to the label.
*
* The following example positions the icon to the right of the
* label:
*
*
* button.label = "Click Me";
* button.defaultIcon = new Image( texture );
* button.iconPosition = RelativePosition.RIGHT;
*
* @default feathers.layout.RelativePosition.LEFT
*
* @see feathers.layout.RelativePosition#TOP
* @see feathers.layout.RelativePosition#RIGHT
* @see feathers.layout.RelativePosition#BOTTOM
* @see feathers.layout.RelativePosition#LEFT
* @see feathers.layout.RelativePosition#RIGHT_BASELINE
* @see feathers.layout.RelativePosition#LEFT_BASELINE
* @see feathers.layout.RelativePosition#MANUAL
*/
public function get iconPosition():String
{
return this._iconPosition;
}
/**
* @private
*/
public function set iconPosition(value:String):void
{
if(this._iconPosition == value)
{
return;
}
this._iconPosition = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _gap:Number = 0;
/**
* The space, in pixels, between the icon and the label. Applies to
* either horizontal or vertical spacing, depending on the value of
* iconPosition
.
*
* If gap
is set to Number.POSITIVE_INFINITY
,
* the label and icon will be positioned as far apart as possible. In
* other words, they will be positioned at the edges of the button,
* adjusted for padding.
*
* The following example creates a gap of 50 pixels between the label
* and the icon:
*
*
* button.label = "Click Me";
* button.defaultIcon = new Image( texture );
* button.gap = 50;
*
* @default 0
*
* @see #iconPosition
* @see #minGap
*/
public function get gap():Number
{
return this._gap;
}
/**
* @private
*/
public function set gap(value:Number):void
{
if(this._gap == value)
{
return;
}
this._gap = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _minGap:Number = 0;
/**
* If the value of the gap
property is
* Number.POSITIVE_INFINITY
, meaning that the gap will
* fill as much space as possible, the final calculated value will not be
* smaller than the value of the minGap
property.
*
* The following example ensures that the gap is never smaller than
* 20 pixels:
*
*
* button.gap = Number.POSITIVE_INFINITY;
* button.minGap = 20;
*
* @default 0
*
* @see #gap
*/
public function get minGap():Number
{
return this._minGap;
}
/**
* @private
*/
public function set minGap(value:Number):void
{
if(this._minGap == value)
{
return;
}
this._minGap = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _horizontalAlign:String = HorizontalAlign.CENTER;
[Inspectable(type="String",enumeration="left,center,right")]
/**
* The location where the button's content is aligned horizontally (on
* the x-axis).
*
* The following example aligns the button's content to the left:
*
*
* button.horizontalAlign = HorizontalAlign.LEFT;
*
* @default feathers.layout.HorizontalAlign.CENTER
*
* @see feathers.layout.HorizontalAlign#LEFT
* @see feathers.layout.HorizontalAlign#CENTER
* @see feathers.layout.HorizontalAlign#RIGHT
*/
public function get horizontalAlign():String
{
return this._horizontalAlign;
}
/**
* @private
*/
public function set horizontalAlign(value:String):void
{
if(this._horizontalAlign == value)
{
return;
}
this._horizontalAlign = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _verticalAlign:String = VerticalAlign.MIDDLE;
[Inspectable(type="String",enumeration="top,middle,bottom")]
/**
* The location where the button's content is aligned vertically (on
* the y-axis).
*
* The following example aligns the button's content to the top:
*
*
* button.verticalAlign = VerticalAlign.TOP;
*
* @default feathers.layout.VerticalAlign.MIDDLE
*
* @see feathers.layout.VerticalAlign#TOP
* @see feathers.layout.VerticalAlign#MIDDLE
* @see feathers.layout.VerticalAlign#BOTTOM
*/
public function get verticalAlign():String
{
return _verticalAlign;
}
/**
* @private
*/
public function set verticalAlign(value:String):void
{
if(this._verticalAlign == value)
{
return;
}
this._verticalAlign = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* 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.
*
* The following example gives the button 20 pixels of padding on all
* sides:
*
*
* button.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, between the button's top edge and the
* button's content.
*
* The following example gives the button 20 pixels of padding on the
* top edge only:
*
*
* button.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, between the button's right edge and the
* button's content.
*
* The following example gives the button 20 pixels of padding on the
* right edge only:
*
*
* button.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, between the button's bottom edge and
* the button's content.
*
* The following example gives the button 20 pixels of padding on the
* bottom edge only:
*
*
* button.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, between the button's left edge and the
* button's content.
*
* The following example gives the button 20 pixels of padding on the
* left edge only:
*
*
* button.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 _labelOffsetX:Number = 0;
/**
* Offsets the x position of the label by a certain number of pixels.
* This does not affect the measurement of the button. The button will
* measure itself as if the label were not offset from its original
* position.
*
* The following example offsets the x position of the button's label
* by 20 pixels:
*
*
* button.labelOffsetX = 20;
*
* @default 0
*
* @see #labelOffsetY
*/
public function get labelOffsetX():Number
{
return this._labelOffsetX;
}
/**
* @private
*/
public function set labelOffsetX(value:Number):void
{
if(this._labelOffsetX == value)
{
return;
}
this._labelOffsetX = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _labelOffsetY:Number = 0;
/**
* Offsets the y position of the label by a certain number of pixels.
* This does not affect the measurement of the button. The button will
* measure itself as if the label were not offset from its original
* position.
*
* The following example offsets the y position of the button's label
* by 20 pixels:
*
*
* button.labelOffsetY = 20;
*
* @default 0
*
* @see #labelOffsetX
*/
public function get labelOffsetY():Number
{
return this._labelOffsetY;
}
/**
* @private
*/
public function set labelOffsetY(value:Number):void
{
if(this._labelOffsetY == value)
{
return;
}
this._labelOffsetY = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _iconOffsetX:Number = 0;
/**
* Offsets the x position of the icon by a certain number of pixels.
* This does not affect the measurement of the button. The button will
* measure itself as if the icon were not offset from its original
* position.
*
* The following example offsets the x position of the button's icon
* by 20 pixels:
*
*
* button.iconOffsetX = 20;
*
* @default 0
*
* @see #iconOffsetY
*/
public function get iconOffsetX():Number
{
return this._iconOffsetX;
}
/**
* @private
*/
public function set iconOffsetX(value:Number):void
{
if(this._iconOffsetX == value)
{
return;
}
this._iconOffsetX = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _iconOffsetY:Number = 0;
/**
* Offsets the y position of the icon by a certain number of pixels.
* This does not affect the measurement of the button. The button will
* measure itself as if the icon were not offset from its original
* position.
*
* The following example offsets the y position of the button's icon
* by 20 pixels:
*
*
* button.iconOffsetY = 20;
*
* @default 0
*
* @see #iconOffsetX
*/
public function get iconOffsetY():Number
{
return this._iconOffsetY;
}
/**
* @private
*/
public function set iconOffsetY(value:Number):void
{
if(this._iconOffsetY == value)
{
return;
}
this._iconOffsetY = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _stateToIconFunction:Function;
/**
* DEPRECATED: Create a feathers.skins.ImageSkin
instead,
* and pass to the defaultIcon
property.
*
* DEPRECATION WARNING: This property 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 function get stateToIconFunction():Function
{
return this._stateToIconFunction;
}
/**
* @private
*/
public function set stateToIconFunction(value:Function):void
{
if(this._stateToIconFunction == value)
{
return;
}
this._stateToIconFunction = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _stateToLabelPropertiesFunction:Function;
/**
* DEPRECATED: Call the appropriate function on the text renderer to set
* different font styles for each state.
*
* DEPRECATION WARNING: This property 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 function get stateToLabelPropertiesFunction():Function
{
return this._stateToLabelPropertiesFunction;
}
/**
* @private
*/
public function set stateToLabelPropertiesFunction(value:Function):void
{
if(this._stateToLabelPropertiesFunction == value)
{
return;
}
this._stateToLabelPropertiesFunction = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* The skin used for the button's up state. If null
, then
* defaultSkin
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToSkinFunction
property.
*
* The following example gives the button a skin for the up state:
*
*
* button.upSkin = new Image( texture );
*
* @default null
*
* @see #defaultSkin
* @see #setSkinForState()
* @see feathers.controls.ButtonState.UP
*/
public function get upSkin():DisplayObject
{
return this.getSkinForState(ButtonState.UP);
}
/**
* @private
*/
public function set upSkin(value:DisplayObject):void
{
this.setSkinForState(ButtonState.UP, value);
}
/**
* The skin used for the button's down state. If null
, then
* defaultSkin
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToSkinFunction
property.
*
* The following example gives the button a skin for the down state:
*
*
* button.downSkin = new Image( texture );
*
* @default null
*
* @see #defaultSkin
* @see #setSkinForState()
* @see feathers.controls.ButtonState.DOWN
*/
public function get downSkin():DisplayObject
{
return this.getSkinForState(ButtonState.DOWN);
}
/**
* @private
*/
public function set downSkin(value:DisplayObject):void
{
this.setSkinForState(ButtonState.DOWN, value);
}
/**
* The skin used for the button's hover state. If null
, then
* defaultSkin
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToSkinFunction
property.
*
* The following example gives the button a skin for the hover state:
*
*
* button.hoverSkin = new Image( texture );
*
* @default null
*
* @see #defaultSkin
* @see #setSkinForState()
* @see feathers.controls.ButtonState.HOVER
*/
public function get hoverSkin():DisplayObject
{
return this.getSkinForState(ButtonState.HOVER);
}
/**
* @private
*/
public function set hoverSkin(value:DisplayObject):void
{
this.setSkinForState(ButtonState.HOVER, value);
}
/**
* The skin used for the button's disabled state. If null
,
* then defaultSkin
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToSkinFunction
property.
*
* The following example gives the button a skin for the disabled state:
*
*
* button.disabledSkin = new Image( texture );
*
* @default null
*
* @see #defaultSkin
* @see #setSkinForState()
* @see feathers.controls.ButtonState.DISABLED
*/
public function get disabledSkin():DisplayObject
{
return this.getSkinForState(ButtonState.DISABLED);
}
/**
* @private
*/
public function set disabledSkin(value:DisplayObject):void
{
this.setSkinForState(ButtonState.DISABLED, value);
}
/**
* @private
*/
protected var _stateToSkinFunction:Function;
/**
* DEPRECATED: Create a feathers.skins.ImageSkin
instead,
* and pass to the defaultSkin
property.
*
* DEPRECATION WARNING: This property 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 function get stateToSkinFunction():Function
{
return this._stateToSkinFunction;
}
/**
* @private
*/
public function set stateToSkinFunction(value:Function):void
{
if(this._stateToSkinFunction == value)
{
return;
}
this._stateToSkinFunction = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _labelFactory:Function;
/**
* A function used to instantiate the button's label text renderer
* sub-component. By default, the button will use the global text
* renderer factory, FeathersControl.defaultTextRendererFactory()
,
* to create the label text renderer. The label text renderer must be an
* instance of ITextRenderer
. To change properties on the
* label text renderer, see defaultLabelProperties
and the
* other "LabelProperties
" properties for each button
* state.
*
* The factory should have the following function signature:
* function():ITextRenderer
*
* The following example gives the button a custom factory for the
* label text renderer:
*
*
* button.labelFactory = function():ITextRenderer
* {
* return new TextFieldTextRenderer();
* }
*
* @default null
*
* @see feathers.core.ITextRenderer
* @see feathers.core.FeathersControl#defaultTextRendererFactory
*/
public function get labelFactory():Function
{
return this._labelFactory;
}
/**
* @private
*/
public function set labelFactory(value:Function):void
{
if(this._labelFactory == value)
{
return;
}
this._labelFactory = value;
this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER);
}
/**
* @private
*/
protected var _customLabelStyleName:String;
/**
* A style name to add to the button's label text renderer
* sub-component. Typically used by a theme to provide different styles
* to different buttons.
*
* In the following example, a custom label style name is passed to
* the button:
*
*
* button.customLabelStyleName = "my-custom-button-label";
*
* In your theme, you can target this sub-component style name to
* provide different styles than the default:
*
*
* getStyleProviderForClass( BitmapFontTextRenderer ).setFunctionForStyleName( "my-custom-button-label", setCustomButtonLabelStyles );
*
* @default null
*
* @see #DEFAULT_CHILD_STYLE_NAME_LABEL
* @see feathers.core.FeathersControl#styleNameList
* @see #labelFactory
*/
public function get customLabelStyleName():String
{
return this._customLabelStyleName;
}
/**
* @private
*/
public function set customLabelStyleName(value:String):void
{
if(this._customLabelStyleName == value)
{
return;
}
this._customLabelStyleName = value;
this.invalidate(INVALIDATION_FLAG_TEXT_RENDERER);
}
/**
* @private
*/
protected var _defaultLabelProperties:PropertyProxy;
/**
* An object that stores properties for the button's label text renderer
* when no specific properties are defined for the button's current
* state, and the properties will be passed down to the label text
* renderer when the button validates. The available properties depend
* on which ITextRenderer
implementation is returned by
* labelFactory
. Refer to
* feathers.core.ITextRenderer
* for a list of available text renderer implementations.
*
* The following example gives the button default label properties to
* use for all states when no specific label properties are available
* (this example assumes that the label text renderer is a
* BitmapFontTextRenderer
):
*
*
* button.defaultLabelProperties.textFormat = new BitmapFontTextFormat( bitmapFont );
* button.defaultLabelProperties.wordWrap = true;
*
* @default null
*
* @see feathers.core.ITextRenderer
*/
public function get defaultLabelProperties():Object
{
if(this._defaultLabelProperties === null)
{
this._defaultLabelProperties = new PropertyProxy(childProperties_onChange);
}
return this._defaultLabelProperties;
}
/**
* @private
*/
public function set defaultLabelProperties(value:Object):void
{
if(!(value is PropertyProxy))
{
value = PropertyProxy.fromObject(value);
}
if(this._defaultLabelProperties !== null)
{
this._defaultLabelProperties.removeOnChangeCallback(childProperties_onChange);
}
this._defaultLabelProperties = PropertyProxy(value);
if(this._defaultLabelProperties !== null)
{
this._defaultLabelProperties.addOnChangeCallback(childProperties_onChange);
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _stateToLabelProperties:Object = {};
/**
* DEPRECATED: Use the appropriate API on the label text renderer to set
* font styles for a particular state.
*
* DEPRECATION WARNING: This property 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 function get upLabelProperties():Object
{
var value:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.UP]);
if(!value)
{
value = new PropertyProxy(childProperties_onChange);
this._stateToLabelProperties[ButtonState.UP] = value;
}
return value;
}
/**
* @private
*/
public function set upLabelProperties(value:Object):void
{
if(!(value is PropertyProxy))
{
value = PropertyProxy.fromObject(value);
}
var oldValue:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.UP]);
if(oldValue)
{
oldValue.removeOnChangeCallback(childProperties_onChange);
}
this._stateToLabelProperties[ButtonState.UP] = value;
if(value)
{
PropertyProxy(value).addOnChangeCallback(childProperties_onChange);
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* DEPRECATED: Use the appropriate API on the label text renderer to set
* font styles for a particular state.
*
* DEPRECATION WARNING: This property 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 function get downLabelProperties():Object
{
var value:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.DOWN]);
if(!value)
{
value = new PropertyProxy(childProperties_onChange);
this._stateToLabelProperties[ButtonState.DOWN] = value;
}
return value;
}
/**
* @private
*/
public function set downLabelProperties(value:Object):void
{
if(!(value is PropertyProxy))
{
value = PropertyProxy.fromObject(value);
}
var oldValue:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.DOWN]);
if(oldValue)
{
oldValue.removeOnChangeCallback(childProperties_onChange);
}
this._stateToLabelProperties[ButtonState.DOWN] = value;
if(value)
{
PropertyProxy(value).addOnChangeCallback(childProperties_onChange);
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* DEPRECATED: Use the appropriate API on the label text renderer to set
* font styles for a particular state.
*
* DEPRECATION WARNING: This property 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 function get hoverLabelProperties():Object
{
var value:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.HOVER]);
if(!value)
{
value = new PropertyProxy(childProperties_onChange);
this._stateToLabelProperties[ButtonState.HOVER] = value;
}
return value;
}
/**
* @private
*/
public function set hoverLabelProperties(value:Object):void
{
if(!(value is PropertyProxy))
{
value = PropertyProxy.fromObject(value);
}
var oldValue:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.HOVER]);
if(oldValue)
{
oldValue.removeOnChangeCallback(childProperties_onChange);
}
this._stateToLabelProperties[ButtonState.HOVER] = value;
if(value)
{
PropertyProxy(value).addOnChangeCallback(childProperties_onChange);
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* DEPRECATED: Use the appropriate API on the label text renderer to set
* font styles for a particular state.
*
* DEPRECATION WARNING: This property 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 function get disabledLabelProperties():Object
{
var value:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.DISABLED]);
if(!value)
{
value = new PropertyProxy(childProperties_onChange);
this._stateToLabelProperties[ButtonState.DISABLED] = value;
}
return value;
}
/**
* @private
*/
public function set disabledLabelProperties(value:Object):void
{
if(!(value is PropertyProxy))
{
value = PropertyProxy.fromObject(value);
}
var oldValue:PropertyProxy = PropertyProxy(this._stateToLabelProperties[ButtonState.DISABLED]);
if(oldValue)
{
oldValue.removeOnChangeCallback(childProperties_onChange);
}
this._stateToLabelProperties[ButtonState.DISABLED] = value;
if(value)
{
PropertyProxy(value).addOnChangeCallback(childProperties_onChange);
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _defaultIcon:DisplayObject;
/**
* The icon used when no other icon is defined for the current state.
* Intended to be used when multiple states should share the same icon.
*
* This property will be ignored if a function is passed to the
* stateToIconFunction
property.
*
* The following example gives the button a default icon to use for
* all states when no specific icon is available:
*
*
* button.defaultIcon = new Image( texture );
*
* @default null
*
* @see #setIconForState()
*/
public function get defaultIcon():DisplayObject
{
return this._defaultIcon;
}
/**
* @private
*/
public function set defaultIcon(value:DisplayObject):void
{
if(this._defaultIcon === value)
{
return;
}
this._defaultIcon = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _stateToIcon:Object = {};
/**
* The icon used for the button's up state. If null
, then
* defaultIcon
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToIconFunction
property.
*
* The following example gives the button an icon for the up state:
*
*
* button.upIcon = new Image( texture );
*
* @default null
*
* @see #defaultIcon
* @see #setIconForState()
* @see feathers.controls.ButtonState.UP
*/
public function get upIcon():DisplayObject
{
return this.getIconForState(ButtonState.UP);
}
/**
* @private
*/
public function set upIcon(value:DisplayObject):void
{
return this.setIconForState(ButtonState.UP, value);
}
/**
* The icon used for the button's down state. If null
, then
* defaultIcon
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToIconFunction
property.
*
* The following example gives the button an icon for the down state:
*
*
* button.downIcon = new Image( texture );
*
* @default null
*
* @see #defaultIcon
* @see #setIconForState()
* @see feathers.controls.ButtonState.DOWN
*/
public function get downIcon():DisplayObject
{
return this.getIconForState(ButtonState.DOWN);
}
/**
* @private
*/
public function set downIcon(value:DisplayObject):void
{
return this.setIconForState(ButtonState.DOWN, value);
}
/**
* The icon used for the button's hover state. If null
, then
* defaultIcon
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToIconFunction
property.
*
* The following example gives the button an icon for the hover state:
*
*
* button.hoverIcon = new Image( texture );
*
* @default null
*
* @see #defaultIcon
* @see #setIconForState()
* @see feathers.controls.ButtonState.HOVER
*/
public function get hoverIcon():DisplayObject
{
return this.getIconForState(ButtonState.HOVER);
}
/**
* @private
*/
public function set hoverIcon(value:DisplayObject):void
{
return this.setIconForState(ButtonState.HOVER, value);
}
/**
* The icon used for the button's disabled state. If null
, then
* defaultIcon
is used instead.
*
* This property will be ignored if a function is passed to the
* stateToIconFunction
property.
*
* The following example gives the button an icon for the disabled state:
*
*
* button.disabledIcon = new Image( texture );
*
* @default null
*
* @see #defaultIcon
* @see #setIconForState()
* @see feathers.controls.ButtonState.DISABLED
*/
public function get disabledIcon():DisplayObject
{
return this.getIconForState(ButtonState.DISABLED);
}
/**
* @private
*/
public function set disabledIcon(value:DisplayObject):void
{
return this.setIconForState(ButtonState.DISABLED, value);
}
/**
* @private
*/
protected var _longPressDuration:Number = 0.5;
/**
* The duration, in seconds, of a long press.
*
* The following example changes the long press duration to one full second:
*
*
* button.longPressDuration = 1.0;
*
* @default 0.5
*
* @see #event:longPress
* @see #isLongPressEnabled
*/
public function get longPressDuration():Number
{
return this._longPressDuration;
}
/**
* @private
*/
public function set longPressDuration(value:Number):void
{
if(this._longPressDuration === value)
{
return;
}
this._longPressDuration = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _isLongPressEnabled:Boolean = false;
/**
* Determines if FeathersEventType.LONG_PRESS
will be
* dispatched.
*
* The following example enables long presses:
*
*
* button.isLongPressEnabled = true;
* button.addEventListener( FeathersEventType.LONG_PRESS, function( event:Event ):void
* {
* // long press
* });
*
* @default false
*
* @see #event:longPress
* @see #longPressDuration
*/
public function get isLongPressEnabled():Boolean
{
return this._isLongPressEnabled;
}
/**
* @private
*/
public function set isLongPressEnabled(value:Boolean):void
{
if(this._isLongPressEnabled === value)
{
return;
}
this._isLongPressEnabled = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _scaleWhenDown:Number = 1;
/**
* The button renders at this scale in the down state.
*
* The following example scales the button in the down state:
*
*
* button.scaleWhenDown = 0.9;
*
* @default 1
*/
public function get scaleWhenDown():Number
{
return this._scaleWhenDown;
}
/**
* @private
*/
public function set scaleWhenDown(value:Number):void
{
this._scaleWhenDown = value;
}
/**
* @private
*/
protected var _scaleWhenHovering:Number = 1;
/**
* The button renders at this scale in the hover state.
*
* The following example scales the button in the hover state:
*
*
* button.scaleWhenHovering = 0.9;
*
* @default 1
*/
public function get scaleWhenHovering():Number
{
return this._scaleWhenHovering;
}
/**
* @private
*/
public function set scaleWhenHovering(value:Number):void
{
this._scaleWhenHovering = value;
}
/**
* @inheritDoc
*/
public function get baseline():Number
{
if(!this.labelTextRenderer)
{
return this.scaledActualHeight;
}
return this.scaleY * (this.labelTextRenderer.y + this.labelTextRenderer.baseline);
}
/**
* @private
*/
protected var _ignoreIconResizes:Boolean = false;
/**
* @private
*/
override public function render(painter:Painter):void
{
var scale:Number = 1;
if(this._currentState === ButtonState.DOWN)
{
scale = this._scaleWhenDown;
}
else if(this._currentState === ButtonState.HOVER)
{
scale = this._scaleWhenHovering;
}
if(scale !== 1)
{
if(this._scaleMatrix === null)
{
this._scaleMatrix = new Matrix();
}
else
{
this._scaleMatrix.identity();
}
this._scaleMatrix.translate(Math.round((1 - scale) / 2 * this.actualWidth),
Math.round((1 - scale) / 2 * this.actualHeight));
this._scaleMatrix.scale(scale, scale);
painter.state.transformModelviewMatrix(this._scaleMatrix);
}
super.render(painter);
}
/**
* @private
*/
override public function dispose():void
{
//we don't dispose it if the button is the parent because it'll
//already get disposed in super.dispose()
if(this._defaultIcon !== null && this._defaultIcon.parent !== this)
{
this._defaultIcon.dispose();
}
for(var state:String in this._stateToIcon)
{
var icon:DisplayObject = this._stateToIcon[state] as DisplayObject;
if(icon !== null && icon.parent !== this)
{
icon.dispose();
}
}
super.dispose();
}
/**
* Gets the icon to be used by the button when its
* currentState
property matches the specified state value.
*
* If a icon is not defined for a specific state, returns
* null
.
*
* @see #setIconForState()
*/
public function getIconForState(state:String):DisplayObject
{
return this._stateToIcon[state] as DisplayObject;
}
/**
* Sets the icon to be used by the button when its
* currentState
property matches the specified state value.
*
* If an icon is not defined for a specific state, the value of the
* defaultIcon
property will be used instead.
*
* @see #defaultIcon
* @see #getIconForState()
* @see feathers.controls.ButtonState
*/
public function setIconForState(state:String, icon:DisplayObject):void
{
if(icon !== null)
{
this._stateToIcon[state] = icon;
}
else
{
delete this._stateToIcon[state];
}
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
override protected function initialize():void
{
super.initialize();
if(!this.keyToTrigger)
{
this.keyToTrigger = new KeyToTrigger(this);
}
if(!this.longPress)
{
this.longPress = new LongPress(this);
this.longPress.tapToTrigger = this.tapToTrigger;
}
}
/**
* @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 textRendererInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_TEXT_RENDERER);
var focusInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_FOCUS);
if(textRendererInvalid)
{
this.createLabel();
}
if(textRendererInvalid || stateInvalid || dataInvalid)
{
this.refreshLabel();
}
if(stylesInvalid || stateInvalid)
{
this.longPress.isEnabled = this._isEnabled && this._isLongPressEnabled;
this.longPress.longPressDuration = this._longPressDuration;
this.keyToTrigger.isEnabled = this._isEnabled;
this.refreshIcon();
}
if(textRendererInvalid || stylesInvalid || stateInvalid)
{
this.refreshLabelStyles();
}
super.draw();
if(textRendererInvalid || stylesInvalid || stateInvalid || dataInvalid || sizeInvalid)
{
this.layoutContent();
}
if(sizeInvalid || focusInvalid)
{
this.refreshFocusIndicator();
}
}
/**
* @private
*/
override protected function autoSizeIfNeeded():Boolean
{
var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN
var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN
var needsMinWidth:Boolean = this._explicitMinWidth !== this._explicitMinWidth; //isNaN
var needsMinHeight:Boolean = this._explicitMinHeight !== this._explicitMinHeight; //isNaN
if(!needsWidth && !needsHeight && !needsMinWidth && !needsMinHeight)
{
return false;
}
var labelRenderer:ITextRenderer = null;
if(this._label !== null && this.labelTextRenderer)
{
labelRenderer = this.labelTextRenderer;
this.refreshMaxLabelSize(true);
this.labelTextRenderer.measureText(HELPER_POINT);
}
var adjustedGap:Number = this._gap;
if(adjustedGap === Number.POSITIVE_INFINITY)
{
adjustedGap = this._minGap;
}
if(this.currentIcon is IValidating)
{
IValidating(this.currentIcon).validate();
}
if(this.currentSkin is IValidating)
{
IValidating(this.currentSkin).validate();
}
var newMinWidth:Number = this._explicitMinWidth;
if(needsMinWidth)
{
if(labelRenderer)
{
newMinWidth = HELPER_POINT.x;
}
else
{
newMinWidth = 0;
}
if(this.currentIcon)
{
if(labelRenderer) //both label and icon
{
if(this._iconPosition !== RelativePosition.TOP && this._iconPosition !== RelativePosition.BOTTOM &&
this._iconPosition !== RelativePosition.MANUAL)
{
newMinWidth += adjustedGap;
if(this.currentIcon is IFeathersControl)
{
newMinWidth += IFeathersControl(this.currentIcon).minWidth;
}
else
{
newMinWidth += this.currentIcon.width;
}
}
else //top, bottom, or manual
{
if(this.currentIcon is IFeathersControl)
{
var iconMinWidth:Number = IFeathersControl(this.currentIcon).minWidth;
if(iconMinWidth > newMinWidth)
{
newMinWidth = iconMinWidth;
}
}
else if(this.currentIcon.width > newMinWidth)
{
newMinWidth = this.currentIcon.width;
}
}
}
else //no label
{
if(this.currentIcon is IFeathersControl)
{
newMinWidth = IFeathersControl(this.currentIcon).minWidth;
}
else
{
newMinWidth = this.currentIcon.width;
}
}
}
newMinWidth += this._paddingLeft + this._paddingRight;
if(this.currentSkin is IFeathersControl)
{
var skinMinWidth:Number = IFeathersControl(this.currentSkin).minWidth;
if(skinMinWidth > newMinWidth)
{
newMinWidth = skinMinWidth;
}
}
else if(this._originalSkinWidth === this._originalSkinWidth && //!isNaN
this._originalSkinWidth > newMinWidth)
{
newMinWidth = this._originalSkinWidth;
}
}
var newMinHeight:Number = this._explicitMinHeight;
if(needsMinHeight)
{
if(labelRenderer)
{
newMinHeight = HELPER_POINT.y;
}
else
{
newMinHeight = 0;
}
if(this.currentIcon)
{
if(labelRenderer) //both label and icon
{
if(this._iconPosition === RelativePosition.TOP || this._iconPosition === RelativePosition.BOTTOM)
{
newMinHeight += adjustedGap;
if(this.currentIcon is IFeathersControl)
{
newMinHeight += IFeathersControl(this.currentIcon).minHeight;
}
else
{
newMinHeight += this.currentIcon.height;
}
}
else //left, right, manual
{
if(this.currentIcon is IFeathersControl)
{
var iconMinHeight:Number = IFeathersControl(this.currentIcon).minHeight;
if(iconMinHeight > newMinHeight)
{
newMinHeight = iconMinHeight;
}
}
else if(this.currentIcon.height > newMinHeight)
{
newMinHeight = this.currentIcon.height;
}
}
}
else //no label
{
if(this.currentIcon is IFeathersControl)
{
newMinHeight = IFeathersControl(this.currentIcon).minHeight;
}
else
{
newMinHeight = this.currentIcon.height;
}
}
}
newMinHeight += this._paddingTop + this._paddingBottom;
if(this.currentSkin is IFeathersControl)
{
var skinMinHeight:Number = IFeathersControl(this.currentSkin).minHeight;
if(skinMinHeight > newMinHeight)
{
newMinHeight = skinMinHeight;
}
}
else if(this._originalSkinHeight === this._originalSkinHeight && //!isNaN
this._originalSkinHeight > newMinHeight)
{
newMinHeight = this._originalSkinHeight;
}
}
var newWidth:Number = this._explicitWidth;
if(needsWidth)
{
if(labelRenderer)
{
newWidth = HELPER_POINT.x;
}
else
{
newWidth = 0;
}
if(this.currentIcon)
{
if(labelRenderer) //both label and icon
{
if(this._iconPosition !== RelativePosition.TOP && this._iconPosition !== RelativePosition.BOTTOM &&
this._iconPosition !== RelativePosition.MANUAL)
{
newWidth += adjustedGap + this.currentIcon.width;
}
else if(this.currentIcon.width > newWidth) //top, bottom, or manual
{
newWidth = this.currentIcon.width;
}
}
else //no label
{
newWidth = this.currentIcon.width;
}
}
newWidth += this._paddingLeft + this._paddingRight;
if(this._originalSkinWidth === this._originalSkinWidth && //!isNaN
this._originalSkinWidth > newWidth)
{
newWidth = this._originalSkinWidth;
}
}
var newHeight:Number = this._explicitHeight;
if(needsHeight)
{
if(labelRenderer)
{
newHeight = HELPER_POINT.y;
}
else
{
newHeight = 0;
}
if(this.currentIcon)
{
if(labelRenderer) //both label and icon
{
if(this._iconPosition === RelativePosition.TOP || this._iconPosition === RelativePosition.BOTTOM)
{
newHeight += adjustedGap + this.currentIcon.height;
}
else if(this.currentIcon.height > newHeight) //left, right, manual
{
newHeight = this.currentIcon.height;
}
}
else //no label
{
newHeight = this.currentIcon.height;
}
}
newHeight += this._paddingTop + this._paddingBottom;
if(this._originalSkinHeight === this._originalSkinHeight && //!isNaN
this._originalSkinHeight > newHeight)
{
newHeight = this._originalSkinHeight;
}
}
return this.saveMeasurements(newWidth, newHeight, newMinWidth, newMinHeight);
}
/**
* @private
*/
override protected function changeState(state:String):void
{
var oldState:String = this._currentState;
if(oldState === state)
{
return;
}
super.changeState(state);
if(this._scaleWhenHovering !== 1 &&
(state === ButtonState.HOVER || oldState === ButtonState.HOVER))
{
this.setRequiresRedraw();
}
else if(this._scaleWhenDown !== 1 &&
(state === ButtonState.DOWN || oldState === ButtonState.DOWN))
{
this.setRequiresRedraw();
}
}
/**
* Creates the label text renderer 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 #labelTextRenderer
* @see #labelFactory
*/
protected function createLabel():void
{
if(this.labelTextRenderer)
{
this.removeChild(DisplayObject(this.labelTextRenderer), true);
this.labelTextRenderer = null;
}
if(this._hasLabelTextRenderer)
{
var factory:Function = this._labelFactory != null ? this._labelFactory : FeathersControl.defaultTextRendererFactory;
this.labelTextRenderer = ITextRenderer(factory());
var labelStyleName:String = this._customLabelStyleName != null ? this._customLabelStyleName : this.labelStyleName;
this.labelTextRenderer.styleNameList.add(labelStyleName);
if(this.labelTextRenderer is IStateObserver)
{
IStateObserver(this.labelTextRenderer).stateContext = this;
}
this.addChild(DisplayObject(this.labelTextRenderer));
}
}
/**
* @private
*/
protected function refreshLabel():void
{
if(!this.labelTextRenderer)
{
return;
}
this.labelTextRenderer.text = this._label;
this.labelTextRenderer.visible = this._label !== null && this._label.length > 0;
this.labelTextRenderer.isEnabled = this._isEnabled;
}
/**
* Sets the currentIcon
property.
*
* For internal use in subclasses.
*/
protected function refreshIcon():void
{
var oldIcon:DisplayObject = this.currentIcon;
this.currentIcon = this.getCurrentIcon();
if(this.currentIcon is IFeathersControl)
{
IFeathersControl(this.currentIcon).isEnabled = this._isEnabled;
}
if(this.currentIcon !== oldIcon)
{
if(oldIcon)
{
if(oldIcon is IFeathersControl)
{
IFeathersControl(oldIcon).removeEventListener(FeathersEventType.RESIZE, currentIcon_resizeHandler);
}
if(oldIcon is IStateObserver)
{
IStateObserver(oldIcon).stateContext = null;
}
this.removeChild(oldIcon, false);
}
if(this.currentIcon)
{
if(this.currentIcon is IStateObserver)
{
IStateObserver(this.currentIcon).stateContext = this;
}
//we want the icon to appear below the label text renderer
var index:int = this.numChildren;
if(this.labelTextRenderer)
{
index = this.getChildIndex(DisplayObject(this.labelTextRenderer));
}
this.addChildAt(this.currentIcon, index);
if(this.currentIcon is IFeathersControl)
{
IFeathersControl(this.currentIcon).addEventListener(FeathersEventType.RESIZE, currentIcon_resizeHandler);
}
}
}
}
/**
* @private
*/
override protected function getCurrentSkin():DisplayObject
{
if(this._stateToSkinFunction !== null)
{
return DisplayObject(this._stateToSkinFunction(this, this._currentState, this.currentSkin));
}
return super.getCurrentSkin();
}
/**
* @private
*/
protected function getCurrentIcon():DisplayObject
{
if(this._stateToIconFunction !== null)
{
return DisplayObject(this._stateToIconFunction(this, this._currentState, this.currentIcon));
}
var result:DisplayObject = this._stateToIcon[this._currentState] as DisplayObject;
if(result !== null)
{
return result;
}
return this._defaultIcon;
}
/**
* @private
*/
protected function refreshLabelStyles():void
{
if(!this.labelTextRenderer)
{
return;
}
var properties:Object = this.getCurrentLabelProperties();
for(var propertyName:String in properties)
{
var propertyValue:Object = properties[propertyName];
this.labelTextRenderer[propertyName] = propertyValue;
}
}
/**
* @private
*/
protected function getCurrentLabelProperties():Object
{
if(this._stateToLabelPropertiesFunction !== null)
{
return this._stateToLabelPropertiesFunction(this, this._currentState);
}
var result:Object = this._stateToLabelProperties[this._currentState];
if(result !== null)
{
return result;
}
return this._defaultLabelProperties;
}
/**
* Positions and sizes the button's content.
*
* For internal use in subclasses.
*/
protected function layoutContent():void
{
var oldIgnoreIconResizes:Boolean = this._ignoreIconResizes;
this._ignoreIconResizes = true;
this.refreshMaxLabelSize(false);
var labelRenderer:DisplayObject = null;
if(this._label !== null && this.labelTextRenderer)
{
this.labelTextRenderer.validate();
labelRenderer = DisplayObject(this.labelTextRenderer);
}
var iconIsInLayout:Boolean = this.currentIcon && this._iconPosition != RelativePosition.MANUAL;
if(labelRenderer && iconIsInLayout)
{
this.positionSingleChild(labelRenderer);
this.positionLabelAndIcon();
}
else if(labelRenderer)
{
this.positionSingleChild(labelRenderer);
}
else if(iconIsInLayout)
{
this.positionSingleChild(this.currentIcon);
}
if(this.currentIcon)
{
if(this._iconPosition == RelativePosition.MANUAL)
{
this.currentIcon.x = this._paddingLeft;
this.currentIcon.y = this._paddingTop;
}
this.currentIcon.x += this._iconOffsetX;
this.currentIcon.y += this._iconOffsetY;
}
if(labelRenderer)
{
this.labelTextRenderer.x += this._labelOffsetX;
this.labelTextRenderer.y += this._labelOffsetY;
}
this._ignoreIconResizes = oldIgnoreIconResizes;
}
/**
* @private
*/
protected function refreshMaxLabelSize(forMeasurement:Boolean):void
{
if(this.currentIcon is IValidating)
{
IValidating(this.currentIcon).validate();
}
var calculatedWidth:Number = this.actualWidth;
var calculatedHeight:Number = this.actualHeight;
if(forMeasurement)
{
calculatedWidth = this._explicitWidth;
if(calculatedWidth !== calculatedWidth) //isNaN
{
calculatedWidth = this._maxWidth;
}
calculatedHeight = this._explicitHeight;
if(calculatedHeight !== calculatedHeight) //isNaN
{
calculatedHeight = this._maxHeight;
}
}
if(this._label != null && this.labelTextRenderer)
{
this.labelTextRenderer.maxWidth = calculatedWidth - this._paddingLeft - this._paddingRight;
this.labelTextRenderer.maxHeight = calculatedHeight - this._paddingTop - this._paddingBottom;
if(this.currentIcon)
{
var adjustedGap:Number = this._gap;
if(adjustedGap == Number.POSITIVE_INFINITY)
{
adjustedGap = this._minGap;
}
if(this._iconPosition == RelativePosition.LEFT || this._iconPosition == RelativePosition.LEFT_BASELINE ||
this._iconPosition == RelativePosition.RIGHT || this._iconPosition == RelativePosition.RIGHT_BASELINE)
{
this.labelTextRenderer.maxWidth -= (this.currentIcon.width + adjustedGap);
}
if(this._iconPosition == RelativePosition.TOP || this._iconPosition == RelativePosition.BOTTOM)
{
this.labelTextRenderer.maxHeight -= (this.currentIcon.height + adjustedGap);
}
}
}
}
/**
* @private
*/
protected function positionSingleChild(displayObject:DisplayObject):void
{
if(this._horizontalAlign == HorizontalAlign.LEFT)
{
displayObject.x = this._paddingLeft;
}
else if(this._horizontalAlign == HorizontalAlign.RIGHT)
{
displayObject.x = this.actualWidth - this._paddingRight - displayObject.width;
}
else //center
{
displayObject.x = this._paddingLeft + Math.round((this.actualWidth - this._paddingLeft - this._paddingRight - displayObject.width) / 2);
}
if(this._verticalAlign == VerticalAlign.TOP)
{
displayObject.y = this._paddingTop;
}
else if(this._verticalAlign == VerticalAlign.BOTTOM)
{
displayObject.y = this.actualHeight - this._paddingBottom - displayObject.height;
}
else //middle
{
displayObject.y = this._paddingTop + Math.round((this.actualHeight - this._paddingTop - this._paddingBottom - displayObject.height) / 2);
}
}
/**
* @private
*/
protected function positionLabelAndIcon():void
{
if(this._iconPosition == RelativePosition.TOP)
{
if(this._gap == Number.POSITIVE_INFINITY)
{
this.currentIcon.y = this._paddingTop;
this.labelTextRenderer.y = this.actualHeight - this._paddingBottom - this.labelTextRenderer.height;
}
else
{
if(this._verticalAlign == VerticalAlign.TOP)
{
this.labelTextRenderer.y += this.currentIcon.height + this._gap;
}
else if(this._verticalAlign == VerticalAlign.MIDDLE)
{
this.labelTextRenderer.y += Math.round((this.currentIcon.height + this._gap) / 2);
}
this.currentIcon.y = this.labelTextRenderer.y - this.currentIcon.height - this._gap;
}
}
else if(this._iconPosition == RelativePosition.RIGHT || this._iconPosition == RelativePosition.RIGHT_BASELINE)
{
if(this._gap == Number.POSITIVE_INFINITY)
{
this.labelTextRenderer.x = this._paddingLeft;
this.currentIcon.x = this.actualWidth - this._paddingRight - this.currentIcon.width;
}
else
{
if(this._horizontalAlign == HorizontalAlign.RIGHT)
{
this.labelTextRenderer.x -= this.currentIcon.width + this._gap;
}
else if(this._horizontalAlign == HorizontalAlign.CENTER)
{
this.labelTextRenderer.x -= Math.round((this.currentIcon.width + this._gap) / 2);
}
this.currentIcon.x = this.labelTextRenderer.x + this.labelTextRenderer.width + this._gap;
}
}
else if(this._iconPosition == RelativePosition.BOTTOM)
{
if(this._gap == Number.POSITIVE_INFINITY)
{
this.labelTextRenderer.y = this._paddingTop;
this.currentIcon.y = this.actualHeight - this._paddingBottom - this.currentIcon.height;
}
else
{
if(this._verticalAlign == VerticalAlign.BOTTOM)
{
this.labelTextRenderer.y -= this.currentIcon.height + this._gap;
}
else if(this._verticalAlign == VerticalAlign.MIDDLE)
{
this.labelTextRenderer.y -= Math.round((this.currentIcon.height + this._gap) / 2);
}
this.currentIcon.y = this.labelTextRenderer.y + this.labelTextRenderer.height + this._gap;
}
}
else if(this._iconPosition == RelativePosition.LEFT || this._iconPosition == RelativePosition.LEFT_BASELINE)
{
if(this._gap == Number.POSITIVE_INFINITY)
{
this.currentIcon.x = this._paddingLeft;
this.labelTextRenderer.x = this.actualWidth - this._paddingRight - this.labelTextRenderer.width;
}
else
{
if(this._horizontalAlign == HorizontalAlign.LEFT)
{
this.labelTextRenderer.x += this._gap + this.currentIcon.width;
}
else if(this._horizontalAlign == HorizontalAlign.CENTER)
{
this.labelTextRenderer.x += Math.round((this._gap + this.currentIcon.width) / 2);
}
this.currentIcon.x = this.labelTextRenderer.x - this._gap - this.currentIcon.width;
}
}
if(this._iconPosition == RelativePosition.LEFT || this._iconPosition == RelativePosition.RIGHT)
{
if(this._verticalAlign == VerticalAlign.TOP)
{
this.currentIcon.y = this._paddingTop;
}
else if(this._verticalAlign == VerticalAlign.BOTTOM)
{
this.currentIcon.y = this.actualHeight - this._paddingBottom - this.currentIcon.height;
}
else
{
this.currentIcon.y = this._paddingTop + Math.round((this.actualHeight - this._paddingTop - this._paddingBottom - this.currentIcon.height) / 2);
}
}
else if(this._iconPosition == RelativePosition.LEFT_BASELINE || this._iconPosition == RelativePosition.RIGHT_BASELINE)
{
this.currentIcon.y = this.labelTextRenderer.y + (this.labelTextRenderer.baseline) - this.currentIcon.height;
}
else //top or bottom
{
if(this._horizontalAlign == HorizontalAlign.LEFT)
{
this.currentIcon.x = this._paddingLeft;
}
else if(this._horizontalAlign == HorizontalAlign.RIGHT)
{
this.currentIcon.x = this.actualWidth - this._paddingRight - this.currentIcon.width;
}
else
{
this.currentIcon.x = this._paddingLeft + Math.round((this.actualWidth - this._paddingLeft - this._paddingRight - this.currentIcon.width) / 2);
}
}
}
/**
* @private
*/
protected function childProperties_onChange(proxy:PropertyProxy, name:Object):void
{
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
override protected function focusInHandler(event:Event):void
{
super.focusInHandler(event);
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_keyDownHandler);
this.stage.addEventListener(KeyboardEvent.KEY_UP, stage_keyUpHandler);
}
/**
* @private
*/
override protected function focusOutHandler(event:Event):void
{
super.focusOutHandler(event);
this.stage.removeEventListener(KeyboardEvent.KEY_DOWN, stage_keyDownHandler);
this.stage.removeEventListener(KeyboardEvent.KEY_UP, stage_keyUpHandler);
if(this.touchPointID >= 0)
{
this.touchPointID = -1;
if(this._isEnabled)
{
this.changeState(ButtonState.UP);
}
else
{
this.changeState(ButtonState.DISABLED);
}
}
}
/**
* @private
*/
protected function stage_keyDownHandler(event:KeyboardEvent):void
{
if(event.keyCode === Keyboard.ESCAPE)
{
this.touchPointID = -1;
this.changeState(ButtonState.UP);
}
if(this.touchPointID >= 0 || event.keyCode !== Keyboard.SPACE)
{
return;
}
this.touchPointID = int.MAX_VALUE;
this.changeState(ButtonState.DOWN);
}
/**
* @private
*/
protected function stage_keyUpHandler(event:KeyboardEvent):void
{
if(this.touchPointID !== int.MAX_VALUE || event.keyCode !== Keyboard.SPACE)
{
return;
}
this.resetTouchState();
}
/**
* @private
*/
protected function currentIcon_resizeHandler():void
{
if(this._ignoreIconResizes)
{
return;
}
this.invalidate(INVALIDATION_FLAG_SIZE);
}
}
}