topical media & game development
student-ar-fl-controls-List.ax
student-ar-fl-controls-List.ax
[swf]
flex
// Copyright 2007. Adobe Systems Incorporated. All Rights Reserved.
package fl.controls {
import fl.data.DataProvider;
import fl.controls.listClasses.CellRenderer;
import fl.controls.listClasses.ICellRenderer;
import fl.controls.listClasses.@fileData;
import fl.controls.ScrollPolicy;
import fl.controls.Selectable@ax-student-ar-fl-controls-List;
import fl.core.InvalidationType;
import fl.core.UIComponent;
import fl.events.DataChangeType;
import fl.events.DataChangeEvent;
import fl.events.@fileEvent;
import fl.events.ScrollEvent;
import fl.managers.IFocusManagerComponent;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import flash.utils.Dictionary;
import flash.geom.Rectangle;
The @ax-student-ar-fl-controls-List component displays list-based information and is ideally suited
for the display of arrays of information.
<p>The @ax-student-ar-fl-controls-List component consists of items, rows, and a data provider, which are
described as follows:</p>
<ul>
<li>Item: An ActionScript object that usually contains a descriptive <code>label</code>
property and a <code>data</code> property that stores the data associated with that item. </li>
<li>Row: A component that is used to display the item. </li>
<li>Data provider: A component that models the items that the @ax-student-ar-fl-controls-List component displays.</li>
</ul>
<p>By default, the @ax-student-ar-fl-controls-List component uses the CellRenderer class to supply the rows in
which list items are displayed. You can create these rows programmatically; this
is usually done by subclassing the CellRenderer class. The CellRenderer class
implements the ICellRenderer interface, which provides the set of properties and
methods that the @ax-student-ar-fl-controls-List component uses to manipulate its rows and to send data and state information
to each row for display. This includes information about data sizing and selection.</p>
<p>The @ax-student-ar-fl-controls-List component provides methods that act on its data provider--for example, the
<code>addItem()</code> and <code>removeItem()</code> methods. You can use these and
other methods to manipulate the data of any array that exists in the same frame as
a @ax-student-ar-fl-controls-List component and then broadcast the changes to multiple views. If a @ax-student-ar-fl-controls-List component
is not provided with an external data provider, these methods automatically create an
instance of a data provider and expose it through the <code>@ax-student-ar-fl-controls-List.dataProvider</code>
property. The @ax-student-ar-fl-controls-List component renders each row by using a Sprite that implements the
ICellRenderer interface. To specify this renderer, use the <code>@ax-student-ar-fl-controls-List.cellRenderer</code>
property. You can also build an Array instance or get one from a server and use it as a
data model for multiple lists, combo boxes, data grids, and so on. </p>
@includeExample examples/@fileExample.as
@langversion 3.0
@playerversion Flash 9.0.28.0
public class @ax-student-ar-fl-controls-List extends Selectable@ax-student-ar-fl-controls-List implements IFocusManagerComponent{
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _rowHeight:Number = 20;
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _cellRenderer:Object;
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _labelField:String="label";
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _labelFunction:Function;
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _iconField:String = "icon";
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
protected var _iconFunction:Function;
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
private static var defaultStyles:Object = {
focusRectSkin:null,
focusRectPadding:null
};
@copy fl.core.UIComponent#getStyleDefinition()
@includeExample ../core/examples/UIComponent.getStyleDefinition.1.as -noswf
see: fl.core.UIComponent#getStyle()
see: fl.core.UIComponent#setStyle()
see: fl.managers.StyleManager
@langversion 3.0
@playerversion Flash 9.0.28.0
public static function getStyleDefinition():Object {
return mergeStyles(defaultStyles, Selectable@ax-student-ar-fl-controls-List.getStyleDefinition());
}
@private
Method for creating the Accessibility class.
This method is called from UIComponent.
@langversion 3.0
@playerversion Flash 9.0.28.0
public static var createAccessibilityImplementation:Function;
Creates a new @ax-student-ar-fl-controls-List component instance.
@langversion 3.0
@playerversion Flash 9.0.28.0
public function @ax-student-ar-fl-controls-List() {
super();
}
Gets or sets the name of the field in the <code>dataProvider</code> object
to be displayed as the label for the TextInput field and drop-down list.
<p>By default, the component displays the <code>label</code> property
of each <code>dataProvider</code> item. If the <code>dataProvider</code>
items do not contain a <code>label</code> property, you can set the
<code>labelField</code> property to use a different property.</p>
<p><strong>Note:</strong> The <code>labelField</code> property is not used
if the <code>labelFunction</code> property is set to a callback function.</p>
@default "label"
see: #labelFunction
@includeExample examples/@ax-student-ar-fl-controls-List.labelField.1.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
public function get labelField():String {
return _labelField;
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set labelField(value:String):void {
if (value == _labelField) { return; }
_labelField = value;
invalidate(InvalidationType.DATA);
}
Gets or sets the function to be used to obtain the label for the item.
<p>By default, the component displays the <code>label</code> property
for a <code>dataProvider</code> item. But some data sets may not have
a <code>label</code> field or may not have a field whose value
can be used as a label without modification. For example, a given data
set might store full names but maintain them in <code>lastName</code> and
<code>firstName</code> fields. In such a case, this property could be
used to set a callback function that concatenates the values of the
<code>lastName</code> and <code>firstName</code> fields into a full
name string to be displayed.</p>
<p><strong>Note:</strong> The <code>labelField</code> property is not used
if the <code>labelFunction</code> property is set to a callback function.</p>
@default null
@includeExample examples/@ax-student-ar-fl-controls-List.labelFunction.1.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
public function get labelFunction():Function {
return _labelFunction;
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set labelFunction(value:Function):void {
if (_labelFunction == value) { return; }
_labelFunction = value;
invalidate(InvalidationType.DATA);
}
Gets or sets the item field that provides the icon for the item.
<p><strong>Note:</strong> The <code>iconField</code> is not used
if the <code>iconFunction</code> property is set to a callback function.</p>
@default "icon"
@includeExample examples/@ax-student-ar-fl-controls-List.iconField.1.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
public function get iconField():String {
return _iconField;
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set iconField(value:String):void {
if (value == _iconField) { return; }
_iconField = value;
invalidate(InvalidationType.DATA);
}
Gets or sets the function to be used to obtain the icon for the item.
<p><strong>Note:</strong> The <code>iconField</code> is not used
if the <code>iconFunction</code> property is set to a callback function.</p>
@default null
@includeExample examples/@ax-student-ar-fl-controls-List.iconFunction.1.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
public function get iconFunction():Function {
return _iconFunction;
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set iconFunction(value:Function):void {
if (_iconFunction == value) { return; }
_iconFunction = value;
invalidate(InvalidationType.DATA);
}
Gets or sets the number of rows that are at least partially visible in the
list.
@includeExample examples/Selectable@ax-student-ar-fl-controls-List.rowCount.1.as -noswf
@includeExample examples/@ax-student-ar-fl-controls-List.rowCount.2.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
override public function get rowCount():uint {
//This is low right now (ie. doesn't count two half items as a whole):
return Math.ceil(calculateAvailableHeight()/rowHeight);
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set rowCount(value:uint):void {
var pad:Number = Number(getStyleValue("contentPadding"));
var scrollBarHeight:Number = (_horizontalScrollPolicy == ScrollPolicy.ON || (_horizontalScrollPolicy == ScrollPolicy.AUTO && _maxHorizontalScrollPosition > 0)) ? 15 : 0;
height = rowHeight*value+2*pad+scrollBarHeight;
}
Gets or sets the height of each row in the list, in pixels.
@default 20
@langversion 3.0
@playerversion Flash 9.0.28.0
public function get rowHeight():Number {
return _rowHeight;
}
@private
@langversion 3.0
@playerversion Flash 9.0.28.0
public function set rowHeight(value:Number):void {
_rowHeight = value;
invalidate(InvalidationType.SIZE);
}
@copy fl.controls.Selectable@ax-student-ar-fl-controls-List#scrollToIndex()
@langversion 3.0
@playerversion Flash 9.0.28.0
override public function scrollToIndex(newCaretIndex:int):void {
drawNow();
var lastVisibleItemIndex:uint = Math.floor((_verticalScrollPosition + availableHeight) / rowHeight) - 1;
var firstVisibleItemIndex:uint = Math.ceil(_verticalScrollPosition / rowHeight);
if(newCaretIndex < firstVisibleItemIndex) {
verticalScrollPosition = newCaretIndex * rowHeight;
} else if(newCaretIndex > lastVisibleItemIndex) {
verticalScrollPosition = (newCaretIndex + 1) * rowHeight - availableHeight;
}
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function configUI():void {
useFixedHorizontalScrolling = true;
_horizontalScrollPolicy = ScrollPolicy.AUTO;
_verticalScrollPolicy = ScrollPolicy.AUTO;
super.configUI();
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
protected function calculateAvailableHeight():Number {
var pad:Number = Number(getStyleValue("contentPadding"));
return height-pad*2-((_horizontalScrollPolicy == ScrollPolicy.ON || (_horizontalScrollPolicy == ScrollPolicy.AUTO && _maxHorizontalScrollPosition > 0)) ? 15 : 0);
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function setHorizontalScrollPosition(value:Number,fireEvent:Boolean=false):void {
list.x = -value;
super.setHorizontalScrollPosition(value, true);
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function setVerticalScrollPosition(scroll:Number,fireEvent:Boolean=false):void {
// This causes problems. It seems like the render event can get "blocked" if it's called from within a callLater
invalidate(InvalidationType.SCROLL);
super.setVerticalScrollPosition(scroll, true);
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function draw():void {
var contentHeightChanged:Boolean = (contentHeight != rowHeight*length);
contentHeight = rowHeight*length;
if (isInvalid(InvalidationType.STYLES)) {
setStyles();
drawBackground();
// drawLayout is expensive, so only do it if padding has changed:
if (contentPadding != getStyleValue("contentPadding")) {
invalidate(InvalidationType.SIZE,false);
}
// redrawing all the cell renderers is even more expensive, so we really only want to do it if necessary:
if (_cellRenderer != getStyleValue("cellRenderer")) {
// remove all the existing renderers:
_invalidate@ax-student-ar-fl-controls-List();
_cellRenderer = getStyleValue("cellRenderer");
}
}
if (isInvalid(InvalidationType.SIZE, InvalidationType.STATE) || contentHeightChanged) {
drawLayout();
}
if (isInvalid(InvalidationType.RENDERER_STYLES)) {
updateRendererStyles();
}
if (isInvalid(InvalidationType.STYLES,InvalidationType.SIZE,InvalidationType.DATA,InvalidationType.SCROLL,InvalidationType.SELECTED)) {
draw@ax-student-ar-fl-controls-List();
}
// Call drawNow on nested components to get around problems with nested render events:
updateChildren();
// Not calling super.draw, because we're handling everything here. Instead we'll just call validate();
validate();
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function draw@ax-student-ar-fl-controls-List():void {
// @ax-student-ar-fl-controls-List is very environmentally friendly, it reuses existing
// renderers for old data, and recycles old renderers for new data.
// set horizontal scroll:
listHolder.x = listHolder.y = contentPadding;
var rect:Rectangle = listHolder.scrollRect;
rect.x = _horizontalScrollPosition;
// set pixel scroll:
rect.y = Math.floor(_verticalScrollPosition)\%rowHeight;
listHolder.scrollRect = rect;
listHolder.cacheAsBitmap = useBitmapScrolling;
// figure out what we have to render:
var startIndex:uint = Math.floor(_verticalScrollPosition/rowHeight);
var endIndex:uint = Math.min(length,startIndex + rowCount+1);
// these vars get reused in different loops:
var i:uint;
var item:Object;
var renderer:ICellRenderer;
// create a dictionary for looking up the new "displayed" items:
var itemHash:Dictionary = renderedItems = new Dictionary(true);
for (i=startIndex; i<endIndex; i++) {
itemHash[_dataProvider.getItemAt(i)] = true;
}
// find cell renderers that are still active, and make those that aren't active available:
var itemToRendererHash:Dictionary = new Dictionary(true);
while (activeCellRenderers.length > 0) {
renderer = activeCellRenderers.pop() as ICellRenderer;
item = renderer.data;
if (itemHash[item] == null || invalidItems[item] == true) {
availableCellRenderers.push(renderer);
} else {
itemToRendererHash[item] = renderer;
// prevent problems with duplicate objects:
invalidItems[item] = true;
}
list.removeChild(renderer as DisplayObject);
}
invalidItems = new Dictionary(true);
// draw cell renderers:
for (i=startIndex; i<endIndex; i++) {
var reused:Boolean = false;
item = _dataProvider.getItemAt(i);
if (itemToRendererHash[item] != null) {
// existing renderer for this item we can reuse:
reused = true;
renderer = itemToRendererHash[item];
delete(itemToRendererHash[item]);
} else if (availableCellRenderers.length > 0) {
// recycle an old renderer:
renderer = availableCellRenderers.pop() as ICellRenderer;
} else {
// out of renderers, create a new one:
renderer = getDisplayObjectInstance(getStyleValue("cellRenderer")) as ICellRenderer;
var rendererSprite:Sprite = renderer as Sprite;
if (rendererSprite != null) {
rendererSprite.addEvent@fileener(MouseEvent.CLICK,handleCellRendererClick,false,0,true);
rendererSprite.addEvent@fileener(MouseEvent.ROLL_OVER,handleCellRendererMouseEvent,false,0,true);
rendererSprite.addEvent@fileener(MouseEvent.ROLL_OUT,handleCellRendererMouseEvent,false,0,true);
rendererSprite.addEvent@fileener(Event.CHANGE,handleCellRendererChange,false,0,true);
rendererSprite.doubleClickEnabled = true;
rendererSprite.addEvent@fileener(MouseEvent.DOUBLE_CLICK,handleCellRendererDoubleClick,false,0,true);
if (rendererSprite.hasOwnProperty("setStyle")) {
for (var n:String in rendererStyles) {
rendererSprite["setStyle"](n, rendererStyles[n])
}
}
}
}
list.addChild(renderer as Sprite);
activeCellRenderers.push(renderer);
renderer.y = rowHeight*(i-startIndex);
renderer.setSize(availableWidth+_maxHorizontalScrollPosition,rowHeight);
var label:String = itemToLabel(item);
var icon:Object = null;
if (_iconFunction != null) {
icon = _iconFunction(item);
} else if (_iconField != null) {
icon = item [iconField];
}
if (!reused) {
renderer.data = item;
}
renderer.listData = new @fileData(label,icon,this,i,i,0);
renderer.selected = (_selectedIndices.indexOf(i) != -1);
// force an immediate draw (because render event will not be called on the renderer):
if (renderer is UIComponent) {
(renderer as UIComponent).drawNow();
}
}
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function keyDownHandler(event:KeyboardEvent):void {
if (!selectable) { return; }
switch (event.keyCode) {
case Keyboard.UP:
case Keyboard.DOWN:
case Keyboard.END:
case Keyboard.HOME:
case Keyboard.PAGE_UP:
case Keyboard.PAGE_DOWN:
moveSelectionVertically(event.keyCode, event.shiftKey && _allowMultipleSelection, event.ctrlKey && _allowMultipleSelection);
break;
case Keyboard.LEFT:
case Keyboard.RIGHT:
moveSelectionHorizontally(event.keyCode, event.shiftKey && _allowMultipleSelection, event.ctrlKey && _allowMultipleSelection);
break;
case Keyboard.SPACE:
if(caretIndex == -1) {
caretIndex = 0;
}
doKeySelection(caretIndex, event.shiftKey, event.ctrlKey);
scrollToSelected();
break;
default:
var nextIndex:int = getNextIndexAtLetter(String.fromCharCode(event.keyCode), selectedIndex);
if (nextIndex > -1) {
selectedIndex = nextIndex;
scrollToSelected();
}
break;
}
event.stopPropagation();
}
@private (protected)
Moves the selection in a horizontal direction in response
to the user selecting items using the left-arrow or right-arrow
keys and modifiers such as the Shift and Ctrl keys.
<p>Not implemented in @ax-student-ar-fl-controls-List because the default list
is single column and therefore doesn't scroll horizontally.</p>
parameter: code The key that was pressed (e.g. Keyboard.LEFT)
parameter: shiftKey true
if the shift key was held down when
the keyboard key was pressed.
parameter: ctrlKey true
if the ctrl key was held down when
the keyboard key was pressed.
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function moveSelectionHorizontally(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {}
@private (protected)
Moves the selection in a vertical direction in response
to the user selecting items using the up-arrow or down-arrow
Keys and modifiers such as the Shift and Ctrl keys.
parameter: code The key that was pressed (e.g. Keyboard.DOWN)
parameter: shiftKey true
if the shift key was held down when
the keyboard key was pressed.
parameter: ctrlKey true
if the ctrl key was held down when
the keyboard key was pressed.
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function moveSelectionVertically(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {
var pageSize:int = Math.max(Math.floor(calculateAvailableHeight() / rowHeight), 1);
var newCaretIndex:int = -1;
var dir:int = 0;
switch(code) {
case Keyboard.UP:
if (caretIndex > 0) {
newCaretIndex = caretIndex - 1;
}
break;
case Keyboard.DOWN:
if (caretIndex < length - 1) {
newCaretIndex = caretIndex + 1;
}
break;
case Keyboard.PAGE_UP:
if (caretIndex > 0) {
newCaretIndex = Math.max(caretIndex - pageSize, 0);
}
break;
case Keyboard.PAGE_DOWN:
if (caretIndex < length - 1) {
newCaretIndex = Math.min(caretIndex + pageSize, length - 1);
}
break;
case Keyboard.HOME:
if (caretIndex > 0) {
newCaretIndex = 0;
}
break;
case Keyboard.END:
if (caretIndex < length - 1) {
newCaretIndex = length - 1;
}
break;
}
if(newCaretIndex >= 0) {
doKeySelection(newCaretIndex, shiftKey, ctrlKey);
scrollToSelected();
}
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
protected function doKeySelection(newCaretIndex:int, shiftKey:Boolean, ctrlKey:Boolean):void {
var selChanged:Boolean = false;
if(shiftKey) {
var i:int;
var selIndices:Array = [];
var startIndex:int = lastCaretIndex;
var endIndex:int = newCaretIndex;
if(startIndex == -1) {
startIndex = caretIndex != -1 ? caretIndex : newCaretIndex;
}
if(startIndex > endIndex) {
endIndex = startIndex;
startIndex = newCaretIndex;
}
for(i = startIndex; i <= endIndex; i++) {
selIndices.push(i);
}
selectedIndices = selIndices;
caretIndex = newCaretIndex;
selChanged = true;
} else {
selectedIndex = newCaretIndex;
caretIndex = lastCaretIndex = newCaretIndex;
selChanged = true;
}
if(selChanged) {
dispatchEvent(new Event(Event.CHANGE));
}
invalidate(InvalidationType.DATA);
}
Retrieves the string that the renderer displays for the given data object
based on the <code>labelField</code> and <code>labelFunction</code> properties.
<p><strong>Note:</strong> The <code>labelField</code> is not used
if the <code>labelFunction</code> property is set to a callback function.</p>
parameter: item The object to be rendered.
returns: The string to be displayed based on the data.
@internal <code>var label:String = my@ax-student-ar-fl-controls-List.itemToLabel(data);</code>
@includeExample examples/@ax-student-ar-fl-controls-List.itemToLabel.1.as -noswf
@langversion 3.0
@playerversion Flash 9.0.28.0
override public function itemToLabel(item:Object):String {
if (_labelFunction != null) {
return String(_labelFunction(item));
} else {
return (item [labelField]!=null) ? String(item [labelField]) : "";
}
}
@private (protected)
@langversion 3.0
@playerversion Flash 9.0.28.0
override protected function initializeAccessibility():void {
if (@ax-student-ar-fl-controls-List.createAccessibilityImplementation != null) {
@ax-student-ar-fl-controls-List.createAccessibilityImplementation(this);
}
}
}
}
(C) Æliens
27/08/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.