// Copyright 2007. Adobe Systems Incorporated. All Rights Reserved. package fl.controls { import fl.controls.listClasses.CellRenderer; import fl.controls.listClasses.ICellRenderer; import fl.controls.listClasses.ImageCell; import fl.controls.listClasses.ListData; import fl.controls.listClasses.student_ar_fl_controls_TileListData; import fl.controls.ScrollBar; import fl.controls.ScrollBarDirection; import fl.controls.ScrollPolicy; import fl.controls.SelectableList; import fl.core.InvalidationType; import fl.core.UIComponent; import fl.data.DataProvider; import fl.data.student_ar_fl_controls_TileListCollectionItem; import fl.events.DataChangeEvent; import fl.events.DataChangeType; import fl.events.ListEvent; import fl.events.ScrollEvent; import fl.managers.IFocusManagerComponent; import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.Event; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import flash.utils.Dictionary; //-------------------------------------- // Events //-------------------------------------- //-------------------------------------- // Styles //-------------------------------------- /** * The skin to be used as the background of the student_ar_fl_controls_TileList component. * * @default student_ar_fl_controls_TileList_skin * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="skin", type="Class")] /** * The cell renderer to be used to render each item in the student_ar_fl_controls_TileList component. * * @default fl.contols.listClasses.ImageCell * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ [Style(name="cellRenderer", type="Class")] //-------------------------------------- // Class description //-------------------------------------- /** * The student_ar_fl_controls_TileList class provides a grid of rows and columns that is typically used * to format and display images in a "tiled" format. The default cell renderer for * this component is the ImageCell class. An ImageCell cell renderer displays a * thumbnail image and a single-line label. To render a list-based cell in a * student_ar_fl_controls_TileList component, use the CellRenderer class. * *

To modify the padding that separates the cell border from the image, you * can globally set the imagePadding style, or set it on the ImageCell * class. Like other cell styles, the imagePadding style cannot be * set on the student_ar_fl_controls_TileList component instance.

* * @see fl.controls.listClasses.CellRenderer * @see fl.controls.listClasses.ImageCell * * @includeExample examples/student_ar_fl_controls_TileListExample.as * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public class student_ar_fl_controls_TileList extends SelectableList implements IFocusManagerComponent{ /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _rowHeight:Number = 50; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _columnWidth:Number = 50; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _scrollDirection:String = ScrollBarDirection.HORIZONTAL; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _scrollPolicy:String = ScrollPolicy.AUTO; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _cellRenderer:Object; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var oldLength:uint = 0; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _labelField:String = "label"; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _labelFunction:Function; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _iconField:String = "icon"; /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected var _iconFunction:Function; /** * @private (protected) */ protected var _sourceField:String = "source"; /** * @private (protected) */ protected var _sourceFunction:Function; /** * @private (protected) */ protected var __rowCount:uint = 0; /** * @private (protected) */ protected var __columnCount:uint = 0; /** * @private */ private var collectionItemImport:student_ar_fl_controls_TileListCollectionItem; /** * @private * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ private static var defaultStyles:Object = { cellRenderer:ImageCell, focusRectSkin:null, focusRectPadding:null, skin:"student_ar_fl_controls_TileList_skin" }; /** * @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, SelectableList.getStyleDefinition(), ScrollBar.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 List component instance. * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function student_ar_fl_controls_TileList() { super(); } [Collection(collectionClass="fl.data.DataProvider", collectionItem="fl.data.student_ar_fl_controls_TileListCollectionItem", identifier="item")] /** * @copy fl.controls.SelectableList#dataProvider * * @includeExample examples/student_ar_fl_controls_TileList.dataProvider.1.as -noswf * @includeExample examples/student_ar_fl_controls_TileList.dataProvider.2.as -noswf * @includeExample examples/student_ar_fl_controls_TileList.dataProvider.3.as -noswf * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function get dataProvider():DataProvider { return super.dataProvider; } /** * @private (setter) */ override public function set dataProvider(value:DataProvider):void { super.dataProvider = value; } /** * Gets or sets a field in each item that contains a label for each tile. * *

Note: The labelField is not used if * the labelFunction property is set to a callback function.

* * @default "label" * * @includeExample examples/student_ar_fl_controls_TileList.labelField.1.as -noswf * * @see #labelFunction * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get labelField():String { return _labelField; } /** * @private (setter) * * @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 a function that indicates the fields of an item that provide the label text for a tile. * *

Note: The labelField is not used if * the labelFunction property is set to a callback function.

* * @default null * * @includeExample examples/student_ar_fl_controls_TileList.labelFunction.1.as -noswf * * @see #labelField * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get labelFunction():Function { return _labelFunction; } /** * @private (setter) * * @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. * *

Note: The iconField is not used * if the iconFunction property is set to a callback function.

* *

Icons can be classes or they can be symbols from the library that have a class name.

* * @default null * * @includeExample examples/student_ar_fl_controls_TileList.iconField.1.as -noswf * * @see #iconFunction * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get iconField():String { return _iconField; } /** * @private (setter) * * @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. * *

Note: The iconField is not used if the * iconFunction property is set to a callback function.

* *

Icons can be classes, or they can be library items that have class names.

* * @default null * * @includeExample examples/student_ar_fl_controls_TileList.iconFunction.1.as -noswf * * @see #iconField * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get iconFunction():Function { return _iconFunction; } /** * @private (setter) * * @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 item field that provides the source path for a tile. * *

Note: The sourceField is not used if the * sourceFunction property is set to a callback function.

* * @default "source" * * @includeExample examples/student_ar_fl_controls_TileList.sourceField.1.as -noswf * * @see #sourceFunction * * @langversion 3.0 * @playerversion Flash 9.0.28.0 * */ public function get sourceField():String { return _sourceField; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set sourceField(value:String):void { _sourceField = value; invalidate(InvalidationType.DATA); } /** * Gets or sets the function to be used to obtain the source path for a tile. * *

Note: The sourceField is not used if the * sourceFunction property is set to a callback function.

* * @default null * * @includeExample examples/student_ar_fl_controls_TileList.sourceFunction.1.as -noswf * * @see #sourceField * * @internal [peter] Check with Metaliq that this is still accurate. * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get sourceFunction():Function { return _sourceFunction; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set sourceFunction(value:Function):void { _sourceFunction = value; invalidate(InvalidationType.DATA); } [Inspectable(defaultValue=0, type="Number")] /** * Gets or sets the number of rows that are at least partially visible * in the list. * *

Setting the rowCount property changes the height of the * list, but the student_ar_fl_controls_TileList component does not maintain this value. It * is important to set the rowCount value after setting the * dataProvider and rowHeight values. The only * exception is if the rowCount is set with the Property * inspector; in this case, the property is maintained until the component * is first drawn.

* * @default 0 * * @includeExample examples/student_ar_fl_controls_TileList.rowCount.1.as -noswf * * @see #columnCount * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function get rowCount():uint { var pad:Number = Number(getStyleValue("contentPadding")); var cols:uint = Math.max(1,(_width-2*pad)/_columnWidth<<0); var rows:uint = Math.max(1,(_height-2*pad)/_rowHeight<<0); if (_scrollDirection == ScrollBarDirection.HORIZONTAL) { if (_scrollPolicy == ScrollPolicy.ON || (_scrollPolicy == ScrollPolicy.AUTO && length > cols*rows)) { // account for horizontal scrollbar: rows = Math.max(1,(_height-2*pad-15)/_rowHeight<<0); } // else use the default rows value from above. } else { // we might have a partial row visible: rows = Math.max(1,Math.ceil((_height-2*pad)/_rowHeight)); } return rows; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set rowCount(value:uint):void { if (value == 0) { return; } if (componentInspectorSetting) { __rowCount = value; return; } __rowCount = 0; var pad:Number = Number(getStyleValue("contentPadding")); var showScroll = (Math.ceil(length/value) > (width/columnWidth)>>0 && _scrollPolicy == ScrollPolicy.AUTO) || _scrollPolicy == ScrollPolicy.ON; height = rowHeight * value + 2*pad + ((_scrollDirection == ScrollBarDirection.HORIZONTAL && showScroll) ? ScrollBar.WIDTH : 0); } [Inspectable(defaultValue=50)] /** * Gets or sets the height that is applied to each row in the list, in pixels. * * @default 50 * * @includeExample examples/student_ar_fl_controls_TileList.rowHeight.1.as -noswf * * @see #columnWidth * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get rowHeight():Number { return _rowHeight; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set rowHeight(value:Number):void { if (_rowHeight == value) { return; } _rowHeight = value; invalidate(InvalidationType.SIZE); } [Inspectable(defaultValue=0, type="Number")] /** * Gets or sets the number of columns that are at least partially visible in the * list. Setting the columnCount property changes the width of the list, * but the student_ar_fl_controls_TileList component does not maintain this value. It is important to set the * columnCount value after setting the dataProvider * and rowHeight values. The only exception is if the rowCount * is set with the Property inspector; in this case, the property is maintained until the * component is first drawn. * * @default 0 * * @includeExample examples/student_ar_fl_controls_TileList.columnCount.1.as -noswf * * @see #rowCount * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get columnCount():uint { var pad:Number = Number(getStyleValue("contentPadding")); var cols:uint = Math.max(1,(_width-2*pad)/_columnWidth<<0); var rows:uint = Math.max(1,(_height-2*pad)/_rowHeight<<0); if (_scrollDirection != ScrollBarDirection.HORIZONTAL) { if (_scrollPolicy == ScrollPolicy.ON || (_scrollPolicy == ScrollPolicy.AUTO && length > cols*rows)) { // account for vertical scrollbar: cols = Math.max(1,(_width-2*pad-15)/_columnWidth<<0); } // else we just use the default cols value from above. } else { // we might have a partial column visible: cols = Math.max(1,Math.ceil((_width-2*pad)/_columnWidth)); } return cols; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set columnCount(value:uint):void { if (value == 0) { return; } if (componentInspectorSetting) { __columnCount = value; return; } __columnCount = 0; var pad:Number = Number(getStyleValue("contentPadding")); var showScroll:Boolean = (Math.ceil(length/value) > (height/rowHeight)>>0 && _scrollPolicy == ScrollPolicy.AUTO) || _scrollPolicy == ScrollPolicy.ON; width = columnWidth*value+2*pad+(_scrollDirection == ScrollBarDirection.VERTICAL && showScroll ? 15 : 0); } [Inspectable(defaultValue=50)] /** * Gets or sets the width that is applied to a column in the list, in pixels. * * @default 50 * * @includeExample examples/student_ar_fl_controls_TileList.columnWidth.1.as -noswf * * @see #rowHeight * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get columnWidth():Number { return _columnWidth; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set columnWidth(value:Number):void { if (_columnWidth == value) { return; } _columnWidth = value; invalidate(InvalidationType.SIZE); } /** * Gets the width of the content area, in pixels. This value is the component width * minus the combined width of the contentPadding value and vertical scroll bar, * if the vertical scroll bar is visible. * * @includeExample examples/student_ar_fl_controls_TileList.innerWidth.1.as -noswf * * @see #innerHeight * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get innerWidth():Number { drawNow(); var contentPadding:Number = getStyleValue("contentPadding") as Number; return width - contentPadding*2 - (_verticalScrollBar.visible ? _verticalScrollBar.width : 0); } /** * Gets the height of the content area, in pixels. This value is the component height * minus the combined height of the contentPadding value and horizontal * scroll bar height, if the horizontal scroll bar is visible. * * @see #innerWidth * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get innerHeight():Number { drawNow(); var contentPadding:Number = getStyleValue("contentPadding") as Number; return height - contentPadding*2 - (_horizontalScrollBar.visible ? _horizontalScrollBar.height : 0); } [Inspectable(enumeration="horizontal,vertical", defaultValue="horizontal")] /** * Gets or sets a value that indicates whether the student_ar_fl_controls_TileList component scrolls * horizontally or vertically. A value of ScrollBarDirection.HORIZONTAL * indicates that the student_ar_fl_controls_TileList component scrolls horizontally; a value of * ScrollBarDirection.VERTICAL indicates that the student_ar_fl_controls_TileList component scrolls vertically. * * @default ScrollBarDirection.VERTICAL * * @includeExample examples/student_ar_fl_controls_TileList.direction.1.as -noswf * * @see ScrollBarDirection * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get direction():String { return _scrollDirection; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set direction(value:String):void { if (_scrollDirection == value) { return; } _scrollDirection = value; invalidate(InvalidationType.SIZE); } [Inspectable(enumeration="auto,on,off", defaultValue="auto")] /** * Gets or sets the scroll policy for the student_ar_fl_controls_TileList component. This * value is used to specify the scroll policy for the scroll bar that * is set by the direction property. * *

Note: The student_ar_fl_controls_TileList component supports scrolling only in * one direction. Tiles are adjusted to fit into the viewable area of * the component, so that tiles are hidden in only one direction.

* *

The student_ar_fl_controls_TileList component resizes to fit tiles only when the user * manually sets the size or when the user sets the rowCount * or columnCount properties.

* *

When this value is set to ScrollPolicy.AUTO, the * scroll bar is visible only when the student_ar_fl_controls_TileList component must scroll * to show all the items.

* * @default ScrollPolicy.AUTO * * @includeExample examples/student_ar_fl_controls_TileList.scrollPolicy.1.as -noswf * * @see #columnCount * @see #rowCount * @see ScrollPolicy * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get scrollPolicy():String { return _scrollPolicy; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function set scrollPolicy(value:String):void { if (!componentInspectorSetting && _scrollPolicy == value) { return; } _scrollPolicy = value; if (direction == ScrollBarDirection.HORIZONTAL) { _horizontalScrollPolicy = value; _verticalScrollPolicy = ScrollPolicy.OFF; } else { _verticalScrollPolicy = value; _horizontalScrollPolicy = ScrollPolicy.OFF; } invalidate(InvalidationType.SIZE); } /** * @copy fl.controls.SelectableList#scrollToIndex() * * @includeExample examples/student_ar_fl_controls_TileList.scrollToIndex.1.as -noswf * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function scrollToIndex(newCaretIndex:int):void { drawNow(); // Force validation. var totalCols:uint = Math.max(1, (contentWidth/_columnWidth<<0)); if (_scrollDirection == ScrollBarDirection.VERTICAL) { if (rowHeight > availableHeight) { return; // nothing: don't scroll if the item is bigger than the viewable area) } var itemY:Number = (newCaretIndex/totalCols>>0) * rowHeight; if (itemY < verticalScrollPosition) { verticalScrollPosition = itemY; } else if (itemY > verticalScrollPosition + availableHeight - rowHeight) { verticalScrollPosition = itemY + rowHeight - availableHeight; } } else { if (columnWidth > availableWidth) { return; } var itemX:Number = newCaretIndex % totalCols * columnWidth; if (itemX < horizontalScrollPosition) { horizontalScrollPosition = itemX; } else if (itemX > horizontalScrollPosition + availableWidth - columnWidth) { horizontalScrollPosition = itemX + columnWidth - availableWidth; } } } /** * Retrieves the string that the renderer displays for a given data object * based on the labelField and labelFunction properties. * * @param item The Object to be rendered. * * @return The string to be displayed based on the data. * * @internal var label:String = mystudent_ar_fl_controls_TileList.itemToLabel(data); * * @see #labelField * @see #labelFunction * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function itemToLabel(item:Object):String { if (_labelFunction != null) { return String(_labelFunction(item)); } else { if (item[_labelField] == null) { return ""; } return String(item[_labelField]); } } // Hide these from the Property inspector and from users. /** * @private (hidden) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function get verticalScrollPolicy():String { return null; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function set verticalScrollPolicy(value:String):void {} /** * @private (hidden) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function get horizontalScrollPolicy():String { return null; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function set horizontalScrollPolicy(value:String):void {} /** * Gets the maximum horizontal scroll position for the current content, in pixels. * * @see fl.containers.BaseScrollPane#horizontalScrollPosition * @see fl.containers.BaseScrollPane#maxVerticalScrollPosition * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function get maxHorizontalScrollPosition():Number { drawNow(); return _maxHorizontalScrollPosition; } /** * @private (setter) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override public function set maxHorizontalScrollPosition(value:Number):void {} /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function configUI():void { super.configUI(); _horizontalScrollPolicy = scrollPolicy; _verticalScrollPolicy = ScrollPolicy.OFF; } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function setHorizontalScrollPosition(scroll:Number,fireEvent:Boolean=false):void { invalidate(InvalidationType.SCROLL); super.setHorizontalScrollPosition(scroll, true); } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function setVerticalScrollPosition(scroll:Number,fireEvent:Boolean=false):void { invalidate(InvalidationType.SCROLL); super.setVerticalScrollPosition(scroll, true); } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function draw():void { // We need to draw the row and column count that are set by component parameters on the first draw. if (direction == ScrollBarDirection.VERTICAL) { if (__rowCount > 0) { rowCount = __rowCount; } if (__columnCount > 0) { columnCount = __columnCount; } } else { if (__columnCount > 0) { columnCount = __columnCount; } if (__rowCount > 0) { rowCount = __rowCount; } } var lengthChanged:Boolean = (oldLength != length); oldLength = 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: _invalidateList(); _cellRenderer = getStyleValue("cellRenderer"); } } if (isInvalid(InvalidationType.SIZE, InvalidationType.STATE) || lengthChanged) { drawLayout(); } // Apply updatedStyles if (isInvalid(InvalidationType.RENDERER_STYLES)) { updateRendererStyles(); } if (isInvalid(InvalidationType.STYLES,InvalidationType.SIZE,InvalidationType.DATA,InvalidationType.SCROLL,InvalidationType.SELECTED)) { drawList(); _maxHorizontalScrollPosition = Math.max(0, contentWidth - availableWidth); } // 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 drawLayout():void { // figure out our scrolling situation: _horizontalScrollPolicy = (_scrollDirection == ScrollBarDirection.HORIZONTAL) ? _scrollPolicy : ScrollPolicy.OFF; _verticalScrollPolicy = (_scrollDirection != ScrollBarDirection.HORIZONTAL) ? _scrollPolicy : ScrollPolicy.OFF; if (_scrollDirection == ScrollBarDirection.HORIZONTAL) { var rows:uint = rowCount; contentHeight = rows*_rowHeight; contentWidth = _columnWidth*Math.ceil(length/rows); } else { var cols:uint = columnCount; contentWidth = cols*_columnWidth; contentHeight = _rowHeight*Math.ceil(length/cols); } // hand off drawing the layout to BaseScrollPane: super.drawLayout(); } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function drawList():void { // these vars get reused in different loops: var i:uint; var itemIndex:uint; var item:Object; var renderer:ICellRenderer; var rows:uint = rowCount; var cols:uint = columnCount; var colW:Number = columnWidth; var rowH:Number = rowHeight; var baseCol:Number = 0; var baseRow:Number = 0; var col:uint; var row:uint; listHolder.x = listHolder.y = contentPadding; // set horizontal scroll: contentScrollRect = listHolder.scrollRect; contentScrollRect.x = Math.floor(_horizontalScrollPosition)%colW; // set pixel scroll: contentScrollRect.y = Math.floor(_verticalScrollPosition)%rowH; listHolder.scrollRect = contentScrollRect; listHolder.cacheAsBitmap = useBitmapScrolling; // figure out what we have to render, and where: var items:Array = []; if (_scrollDirection == ScrollBarDirection.HORIZONTAL) { // horizontal scrolling is trickier if we want to keep tiles going left to right, then top to bottom. // we can use availableWidth / availableHeight from BaseScrollPane here, because we've just called drawLayout, so we know they are accurate. var fullCols:uint = availableWidth/colW<<0; var rowLength:uint = Math.max(fullCols,Math.ceil(length/rows)); baseCol = _horizontalScrollPosition/colW<<0; cols = Math.max(fullCols,Math.min(rowLength-baseCol,cols+1));//(horizontalScrollBar.visible ? 1 : -1))); // need to draw an extra two cols for scrolling. //rowLength = Math.max(cols-(horizontalScrollBar.visible ? -1 : 0),rowLength); for (row=0; row= length) { break; } items.push(itemIndex); } } } else { rows++; // need to draw an extra row for scrolling. baseRow = _verticalScrollPosition/rowH<<0; var startIndex:uint = Math.floor(baseRow*cols); var endIndex:uint = Math.min(length,startIndex+rows*cols); for (i=startIndex; i 0) { renderer = activeCellRenderers.pop(); 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); i = 0; // count of items placed. // draw cell renderers: for each (itemIndex in items) { col = i%cols; row = i/cols<<0; var reused:Boolean = false; item = _dataProvider.getItemAt(itemIndex); 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.addEventListener(MouseEvent.CLICK,handleCellRendererClick,false,0,true); rendererSprite.addEventListener(MouseEvent.ROLL_OVER,handleCellRendererMouseEvent,false,0,true); rendererSprite.addEventListener(MouseEvent.ROLL_OUT,handleCellRendererMouseEvent,false,0,true); rendererSprite.addEventListener(Event.CHANGE,handleCellRendererChange,false,0,true); rendererSprite.doubleClickEnabled = true; rendererSprite.addEventListener(MouseEvent.DOUBLE_CLICK,handleCellRendererDoubleClick,false,0,true); if (rendererSprite["setStyle"] != null) { for (var n:String in rendererStyles) { rendererSprite["setStyle"](n, rendererStyles[n]) } } } } list.addChild(renderer as Sprite); activeCellRenderers.push(renderer); renderer.y = rowH*row; renderer.x = colW*col; renderer.setSize(columnWidth,rowHeight); var label:String = itemToLabel(item); var icon:Object = null; if (_iconFunction != null) { icon = _iconFunction(item); } else if (_iconField != null) { icon = item[_iconField]; } var source:Object = null; if (_sourceFunction != null) { source = _sourceFunction(item); } else if (_sourceField != null) { source = item[_sourceField]; } if (!reused) { renderer.data = item; } renderer.listData = new student_ar_fl_controls_TileListData(label,icon,source,this,itemIndex,baseRow+row,baseCol+col) as ListData; renderer.selected = (_selectedIndices.indexOf(itemIndex) != -1); // force an immediate draw (because render event will not be called on the renderer): if (renderer is UIComponent) { var rendererUIC:UIComponent = renderer as UIComponent; rendererUIC.drawNow(); } i++; } } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function keyDownHandler(event:KeyboardEvent):void { event.stopPropagation(); if (!selectable) { return; } switch (event.keyCode) { case Keyboard.UP: case Keyboard.DOWN: moveSelectionVertically(event.keyCode, event.shiftKey && _allowMultipleSelection, event.ctrlKey && _allowMultipleSelection); break; case Keyboard.PAGE_UP: case Keyboard.PAGE_DOWN: case Keyboard.END: case Keyboard.HOME: if (_scrollDirection == ScrollBarDirection.HORIZONTAL) { moveSelectionHorizontally(event.keyCode, event.shiftKey && _allowMultipleSelection, event.ctrlKey && _allowMultipleSelection); } else { 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; default: var nextIndex:int = getNextIndexAtLetter(String.fromCharCode(event.keyCode), selectedIndex); if (nextIndex > -1) { selectedIndex = nextIndex; scrollToSelected(); } break; } } /** * @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) * 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. * * @param code The key that was pressed (e.g. Keyboard.DOWN) * * @param shiftKey true if the shift key was held down when * the keyboard key was pressed. * * @param 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 totalRows:uint = Math.max(1, (Math.max(contentHeight,availableHeight)/_rowHeight<<0)); var perRow:uint = Math.ceil(Math.max(columnCount*rowCount,length) / totalRows); // This is wrong. var totalContentRows:uint = Math.ceil(length / perRow); var index:int; var newIndex:int; switch (code) { case Keyboard.UP: index = selectedIndex - perRow; break; case Keyboard.DOWN: index = selectedIndex + perRow; break; case Keyboard.HOME: index = 0; break; case Keyboard.END: index = length-1; break; case Keyboard.PAGE_DOWN: newIndex = selectedIndex + perRow * (totalContentRows-1); if (newIndex >= length) { newIndex -= perRow; } index = Math.min(length-1, newIndex); break; case Keyboard.PAGE_UP: newIndex = selectedIndex - perRow * (totalContentRows-1); if (newIndex < 0) { newIndex += perRow; } index = Math.max(0, newIndex); break; } doKeySelection(index, shiftKey, ctrlKey); scrollToSelected(); } /** * @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. * *

Not implemented in List because the default list * is single column and does not scroll horizontally.

* * @param code The key that was pressed (e.g. Keyboard.LEFT) * * @param shiftKey true if the shift key was held down when * the keyboard key was pressed. * * @param 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 { var totalCols:uint = Math.ceil(Math.max(rowCount*columnCount,length) / rowCount); var index:int; switch(code) { case Keyboard.LEFT: index = Math.max(0, selectedIndex - 1); break; case Keyboard.RIGHT: index = Math.min(length-1, selectedIndex + 1); break; case Keyboard.HOME: index = 0; break; case Keyboard.END: index = length-1; break; case Keyboard.PAGE_UP: var firstIndex:int = selectedIndex - selectedIndex%totalCols; index = Math.max(0, Math.max(firstIndex, selectedIndex - columnCount)); break; case Keyboard.PAGE_DOWN: var lastIndex = selectedIndex - selectedIndex%totalCols + totalCols-1; index = Math.min(length-1, Math.min(lastIndex, selectedIndex + totalCols)); break; } doKeySelection(index, shiftKey, ctrlKey); scrollToSelected(); } /** * @private (protected) * Changes the selected index, or adds or subtracts the index and * all indices between when the shift key is used. * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ protected function doKeySelection(newCaretIndex:uint, shiftKey:Boolean, ctrlKey:Boolean):void { var indices:Array = selectedIndices; var selChanged:Boolean = false; if (newCaretIndex < 0 || newCaretIndex > length-1) { // The index is out of range, do nothing. } else if (shiftKey && indices.length > 0 && newCaretIndex != indices[0]) { var firstIndex:uint = indices[0]; indices = []; var i:int; if (newCaretIndex < firstIndex) { for (i=firstIndex; i>=newCaretIndex; i--) { indices.push(i); } } else { for (i=firstIndex; i<=newCaretIndex; i++) { indices.push(i); } } selChanged = true; } else { indices = [newCaretIndex]; caretIndex = newCaretIndex; selChanged = true; } selectedIndices = indices; if(selChanged) { dispatchEvent(new Event(Event.CHANGE)); } invalidate(InvalidationType.DATA); } /** * @private (protected) * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ override protected function initializeAccessibility():void { if (student_ar_fl_controls_TileList.createAccessibilityImplementation != null) { student_ar_fl_controls_TileList.createAccessibilityImplementation(this); } } } }