// Copyright 2007. Adobe Systems Incorporated. All Rights Reserved. package fl.core { import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.display.InteractiveObject; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.events.EventPhase; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.geom.Rectangle; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFormatAlign; import flash.utils.Dictionary; import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; import flash.system.Capabilities; import flash.system.IME; import flash.system.IMEConversionMode; import flash.utils.getQualifiedClassName; import fl.core.InvalidationType; import fl.events.ComponentEvent; import fl.managers.FocusManager; import fl.managers.IFocusManager; import fl.managers.IFocusManagerComponent; import fl.managers.StyleManager; //-------------------------------------- // Events //-------------------------------------- /** * Dispatched after the component is moved. * * @eventType fl.events.ComponentEvent.MOVE * * @includeExample examples/student_ar_fl_core_UIComponent.MOVE.1.as -noswf * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Event(name="move", type="fl.events.ComponentEvent")] /** * Dispatched after the component is resized. * * @eventType fl.events.ComponentEvent.RESIZE * * @includeExample examples/student_ar_fl_core_UIComponent.RESIZE.1.as -noswf * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Event(name="resize", type="fl.events.ComponentEvent")] /** * Dispatched after the component visibility changes from invisible to visible. * * @eventType fl.events.ComponentEvent.SHOW * * @includeExample examples/student_ar_fl_core_UIComponent.HIDE.1.as -noswf * * @see #event:hide * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Event(name="show", type="fl.events.ComponentEvent")] /** * Dispatched after the component visibility changes from visible to invisible. * * @eventType fl.events.ComponentEvent.HIDE * * @includeExample examples/student_ar_fl_core_UIComponent.HIDE.1.as -noswf * * @see #event:show * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Event(name="hide", type="fl.events.ComponentEvent")] //-------------------------------------- // Styles //-------------------------------------- /** * The skin to be used to display focus indicators. * * @default focusRectSkin * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="focusRectSkin", type="Class")] /** * The padding that separates the outside boundaries of the component from the * outside edges of the focus indicator, in pixels. * * @default 2 * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="focusRectPadding", type="Number", format="Length")] /** * The TextFormat object to use to render the component label. * * @default TextFormat("_sans", 11, 0x000000, false, false, false, '', '', TextFormatAlign.LEFT, 0, 0, 0, 0) * * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="textFormat", type="flash.text.TextFormat")] /** * The TextFormat object to use to render the component label when the button is disabled. * * @default TextFormat("_sans", 11, 0x999999, false, false, false, '', '', TextFormatAlign.LEFT, 0, 0, 0, 0) * * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="disabledTextFormat", type="flash.text.TextFormat")] //-------------------------------------- // Class description //-------------------------------------- /** * The student_ar_fl_core_UIComponent class is the base class for all visual components, * both interactive and noninteractive. Interactive components are defined * as components that receive user input such as keyboard or mouse activity. * Noninteractive components are used to display data; they do not respond * to user interaction. The ProgressBar and UILoader components are examples * of noninteractive components. * *
The Tab and arrow keys can be used to move focus to and over an interactive component; * an interactive component can accept low-level events such as input from mouse and keyboard * devices. An interactive component can also be disabled so that it cannot receive * mouse and keyboard input.
* * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public class student_ar_fl_core_UIComponent extends Sprite { /** * The version number of the components. * * @includeExample examples/student_ar_fl_core_UIComponent.version.1.as -noswf * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public var version:String = "3.0.0.16"; /** * @private (internal) * Indicates whether the current execution stack is within a call later phase. * * @default false * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public static var inCallLaterPhase:Boolean=false; /** * @private * Used when components are nested, and we want the parent component to * handle draw focus, not the child. * * @default null * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public var focusTarget:IFocusManagerComponent; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var isLivePreview:Boolean = false; /** * @private (testing) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private var tempText:TextField; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var instanceStyles:Object; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var sharedStyles:Object; // Holds a reference to the class-level styles. /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var callLaterMethods:Dictionary; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var invalidateFlag:Boolean = false; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _enabled:Boolean=true; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var invalidHash:Object; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var uiFocusRect:DisplayObject; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var isFocused:Boolean = false /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private var _focusEnabled:Boolean = true; /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private var _mouseFocusEnabled:Boolean = true; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _width:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _height:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _x:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _y:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var startWidth:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var startHeight:Number; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _imeMode:String = null; /** * @private (protected) */ protected var _oldIMEMode:String = null; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var errorCaught:Boolean = false; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _inspector:Boolean = false; /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private static var defaultStyles:Object = { focusRectSkin:"focusRectSkin", focusRectPadding:2, textFormat: new TextFormat("_sans", 11, 0x000000, false, false, false, "", "", TextFormatAlign.LEFT, 0, 0, 0, 0), disabledTextFormat: new TextFormat("_sans", 11, 0x999999, false, false, false, "", "", TextFormatAlign.LEFT, 0, 0, 0, 0), defaultTextFormat: new TextFormat("_sans", 11, 0x000000, false, false, false, "", "", TextFormatAlign.LEFT, 0, 0, 0, 0), defaultDisabledTextFormat: new TextFormat("_sans", 11, 0x999999, false, false, false, "", "", TextFormatAlign.LEFT, 0, 0, 0, 0) } /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private static var focusManagers:Dictionary = new Dictionary(false); /** * Retrieves the default style map for the current component. The style map contains * the type that is appropriate for the component, depending on the style that * the component uses. For example, thedisabledTextFormat
style
* contains a value of null
or a TextFormat object.
* You can use these styles and call setStyle()
on the current
* component. The following code overrides the default disabledTextFormat
* style on the specified component:
* false
indicates that it cannot.
*
* If you set the enabled
property to false
, the color of the
* container is dimmed and user input is blocked (with the exception of the Label and ProgressBar components).
Setting this property causes a resize
event to be
* dispatched. See the resize
event for detailed information
* about when it is dispatched.
If the scaleX
property of the component is not 1.0,
* the width of the component that is obtained from its internal coordinates
* will not match the width value from the parent coordinates. For example,
* a component that is 100 pixels in width and has a scaleX
of 2
* has a value of 100 pixels in the parent, but internally stores a value
* indicating that it is 50 pixels wide.
Setting this property causes a resize
event to be
* dispatched. See the resize
event for detailed information
* about when it is dispatched.
If the scaleY
property of the component is not 1.0,
* the height of the component that is obtained from its internal coordinates
* will not match the height value from the parent coordinates. For example,
* a component that is 100 pixels in height and has a scaleY
of 2
* has a value of 100 pixels in the parent, but internally stores a value
* indicating that it is 50 pixels in height.
Calling this method can result in decreased performance. * Use it only when necessary.
* * @param style The name of the style property. * * @param value The value of the style. * * @includeExample examples/student_ar_fl_core_UIComponent.setStyle.1.as -noswf * @includeExample examples/student_ar_fl_core_UIComponent.setStyle.2.as -noswf * * @see #getStyle() * @see #clearStyle() * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function setStyle(style:String, value:Object):void { //Use strict equality so we can set a style to null ... so if the instanceStyles[style] == undefined, null is still set. //We also need to work around the specific use case of TextFormats if (instanceStyles[style] === value && !(value is TextFormat)) { return; } instanceStyles[style] = value; invalidate(InvalidationType.STYLES); } /** * Deletes a style property from this component instance. *This does not necessarily cause the getStyle()
method
* to return a value of undefined
.
The type that this method returns varies depending on the style * property that the method retrieves. The range of possible types includes * Boolean; String; Number; int; a uint for an RGB color; a Class for a skin; * or any kind of object.
* *If you call this method to retrieve a particular style property, * it will be of a known type that you can store in a variable of the * same type. Type casting is not necessary. Instead, a simple assignment * statement like the following will work:
* *If the style property is not set in the style lookup chain, this method
* returns a value of undefined
. Note that undefined
* is a special value that is not the same as false
, "", NaN
,
* 0, or null
. No valid style value is ever undefined
.
* You can use the static method StyleManager.isValidStyleValue()
to
* test whether a value was set.
x
and y
properties. Calling this method triggers
* the ComponentEvent.MOVE
event to be dispatched.
*
* To override the updateDisplayList()
method in a
* custom component, use the move()
method instead
* of setting the x
and y
properties. This is because
* a call to the move()
method causes a move
event object
* to be dispatched immediately after the move operation is complete. In contrast,
* when you change the component location by setting the x
and y
* properties, the event object is dispatched on the next screen refresh.
Setting this property causes the ComponentEvent.MOVE
event to be dispatched.
Setting this property causes the move
event to be dispatched.
true
indicates that the current component is visible; a value of
* false
indicates that it is not.
*
* When this property is set to true
, the object dispatches a
* show
event. When this property is set to false
,
* the object dispatches a hide
event. In either case,
* the children of the object do not generate a show
or
* hide
event unless the object specifically writes an
* implementation to do so.
Properties that require substantial computation are normally not processed
* until the script finishes executing. This is because setting one property could
* require the processing of other properties. For example, setting the width
* property may require that the widths of the children or parent of the object also
* be recalculated. And if the script recalculates the width of the object more than
* once, these interdependent properties may also require recalculating. Use this
* method to manually override this behavior.
true
.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function invalidate(property:String=InvalidationType.ALL,callLater:Boolean=true):void {
invalidHash[property] = true;
if (callLater) { this.callLater(draw); }
}
/**
* @private (internal)
*
* Sets the inherited style value to the specified style name and
* invalidates the styles of the component.
*
* @param name Style name.
*
* @param style Style value.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function setSharedStyle(name:String,style:Object):void {
if (sharedStyles[name] === style && !(style is TextFormat)) { return; }
sharedStyles[name] = style;
if (instanceStyles[name] == null) {
invalidate(InvalidationType.STYLES);
}
}
/**
* Gets or sets a Boolean value that indicates whether the component can receive focus
* after the user clicks it. A value of true
indicates that it can
* receive focus; a value of false
indicates that it cannot.
*
* If this property is false
, focus is transferred to the first
* parent whose mouseFocusEnabled
property is set to true
.
true
indicates that it can receive
* focus; a value of false
indicates that it cannot.
*
* If this property is false
, focus is transferred to the first
* parent whose mouseFocusEnabled
property is set to true
.
null
.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get focusManager():IFocusManager {
var o:DisplayObject = this;
while (o) {
if (student_ar_fl_core_UIComponent.focusManagers[o] != null) {
return IFocusManager(student_ar_fl_core_UIComponent.focusManagers[o]);
}
o = o.parent;
}
return null;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set focusManager(f:IFocusManager):void {
student_ar_fl_core_UIComponent.focusManagers[this] = f;
}
/**
* Shows or hides the focus indicator on this component.
*
* The student_ar_fl_core_UIComponent class implements this method by creating and positioning
* an instance of the class that is specified by the focusSkin
style.
true
, the focus indicator is shown; if this value
* is false
, the focus indicator is hidden.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function drawFocus(focused:Boolean):void {
isFocused = focused; // We need to set isFocused here since there are drawFocus() calls from FM.
//Remove uiFocusRect if focus is turned off
if (uiFocusRect != null && contains(uiFocusRect)) {
removeChild(uiFocusRect);
uiFocusRect = null;
}
//Add focusRect to stage, and resize. If component is focused.
if (focused) {
uiFocusRect = getDisplayObjectInstance(getStyleValue("focusRectSkin")) as Sprite;
if (uiFocusRect == null) { return; }
var focusPadding:Number = Number(getStyleValue("focusRectPadding"));
uiFocusRect.x = -focusPadding;
uiFocusRect.y = -focusPadding;
uiFocusRect.width = width + (focusPadding*2);
uiFocusRect.height = height + (focusPadding*2);
addChildAt(uiFocusRect, 0);
}
}
/**
* Sets the focus to this component. The component may in turn give the focus
* to a subcomponent.
*
* Note: Only the TextInput and TextArea components show * a focus indicator when this method sets the focus. All components show a focus * indicator when the user tabs to the component.
* * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function setFocus():void { if (stage) { stage.focus = this; } } /** * Retrieves the object that currently has focus. * *Note that this method does not necessarily return the component that
* has focus. It may return the internal subcomponent of the component
* that has focus. To get the component that has focus, use the
* focusManager.focus
property.
null
.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function getFocus():InteractiveObject {
if (stage) {
return stage.focus;
}
return null;
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function setIMEMode(enabled:Boolean) {
if(_imeMode != null) {
if(enabled) {
IME.enabled = true;
_oldIMEMode = IME.conversionMode;
try {
if (!errorCaught && IME.conversionMode != IMEConversionMode.UNKNOWN) {
IME.conversionMode = _imeMode;
}
errorCaught = false;
} catch(e:Error) {
errorCaught = true;
throw new Error("IME mode not supported: " + _imeMode);
}
} else {
if (IME.conversionMode != IMEConversionMode.UNKNOWN && _oldIMEMode != IMEConversionMode.UNKNOWN) {
IME.conversionMode = _oldIMEMode;
}
IME.enabled = false;
}
}
}
/**
* Initiates an immediate draw operation, without invalidating everything as invalidateNow
does.
*
* @internal what is "invalidateNow"? i cannot find it in the API.
* @internal [kenos] Additionally, is the immediate draw operation on this component and does invalidating
* "everything" mean invalidating the entire component?
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function drawNow():void {
draw();
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function configUI():void {
isLivePreview = checkLivePreview();
var r:Number = rotation;
rotation = 0;
var w:Number = super.width;
var h:Number = super.height;
super.scaleX = super.scaleY = 1;
setSize(w,h);
move(super.x,super.y);
rotation = r;
startWidth = w;
startHeight = h;
if (numChildren > 0) {
removeChildAt(0);
}
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function checkLivePreview():Boolean {
if (parent == null) { return false; }
var className:String;
try {
className = getQualifiedClassName(parent);
} catch (e:Error) {}
return (className == "fl.livepreview::LivePreviewParent");
}
// Included the first property as a proper param to enable *some* type checking, and also because it is a required param.
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function isInvalid(property:String,...properties:Array):Boolean {
if (invalidHash[property] || invalidHash[InvalidationType.ALL]) { return true; }
while (properties.length > 0) {
if (invalidHash[properties.pop()]) { return true; }
}
return false
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function validate():void {
invalidHash = {};
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function draw():void {
// classes that extend student_ar_fl_core_UIComponent should deal with each possible invalidated property
// common values include all, size, enabled, styles, state
// draw should call super or validate when finished updating
if (isInvalid(InvalidationType.SIZE,InvalidationType.STYLES)) {
if (isFocused && focusManager.showFocusIndicator) { drawFocus(true); }
}
validate();
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected function getDisplayObjectInstance(skin:Object):DisplayObject {
var classDef:Object = null;
if (skin is Class) {
return (new skin()) as DisplayObject;
} else if (skin is DisplayObject) {
(skin as DisplayObject).x = 0;
(skin as DisplayObject).y = 0;
return skin as DisplayObject;
}
try {
classDef = getDefinitionByName(skin.toString());
} catch(e:Error) {
try {
classDef = loaderInfo.applicationDomain.getDefinition(skin.toString()) as Object;
} catch (e:Error) {
// Nothing
}
}
if (classDef == null) {
return null;
}
return (new classDef()) as DisplayObject;
}
/**
* Returns the specified style for a component, considering all styles set on the global level, component level and instance level.
*
* For example, if a component has a style set at the global level to myStyle
and you call
* getStyle("myStyle")
on an instance that does not have an instance setting, it returns null. If you call
* getStyleValue("myStyle")
, it returns "myStyle", because it is active at the global level.
This method is called from the constructor via ENTER_FRAME event * to initialize accessibility support for this component
* * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected function hookAccessibility(event:Event):void { removeEventListener(Event.ENTER_FRAME, hookAccessibility); initializeAccessibility(); } /** * @private (protected) * Initializes this component's accessibility code. * *This method is called from the constructor to hook in the * component's accessibility code, which resides in a separate class * in the fl.accessibility package. * Each subclass that supports accessibility must override this method * because the hook-in process uses a different static variable * in each subclass.
* * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected function initializeAccessibility():void { if (student_ar_fl_core_UIComponent.createAccessibilityImplementation != null) { student_ar_fl_core_UIComponent.createAccessibilityImplementation(this); } } } }