Flex 3 MouseSelectable TileList V3:
/*
MouseSelectableTileList V3 for Flex 3
Ticore Shih
http://ticore.blogspot.com/
MouseSelectableTileList Structure
│
└─┬mouseSelectRect
│
└listContent
│
├items
│
└selectionLayer
*/
package com.ticore.uicomponents {
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.utils.*;
import mx.collections.CursorBookmark;
import mx.collections.ItemResponder;
import mx.collections.ItemWrapper;
import mx.collections.ModifiedCollectionView;
import mx.collections.errors.ItemPendingError;
import mx.controls.TileList;
import mx.controls.listClasses.*;
import mx.core.*;
import mx.events.*;
use namespace mx_internal;
public class MouseSelectableTileList extends TileList {
public function MouseSelectableTileList():void{
super();
if (VERSION != "3.0.0.0") {
throw new Error("Super class version incompatible !");
}
init();
}
protected function init():void{
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.addEventListener(KeyboardEvent.KEY_DOWN, onKeyboardEvent);
this.addEventListener(KeyboardEvent.KEY_UP, onKeyboardEvent);
}
protected function onKeyboardEvent(evtObj:KeyboardEvent):void{
this.ctrlKey = evtObj.ctrlKey;
this.shiftKey = evtObj.shiftKey;
}
override protected function createChildren():void{
super.createChildren();
if (!mouseSelectRect) {
mouseSelectRect = new FlexSprite();
mouseSelectRect.name = "mouseSelectRect";
this.addChild(mouseSelectRect);
}
}
//=================================================================
// Protected Properties
//=================================================================
[Bindable]
public var itemMargin:Number = 10;
//=================================================================
// Protected Properties
//=================================================================
private var mouseDragScrollingInterval:int = 0;
protected var mouseSelectRect:FlexSprite;
protected var startPoint:Point;
protected var endPoint:Point;
protected var startIndexPoint:Point;
protected var endIndexPoint:Point;
protected var ctrlKey:Boolean = false;
protected var shiftKey:Boolean = false;
protected var oldSelectedIndices:Array;
//=================================================================
// Mouse Event Handlers
//=================================================================
protected function onMouseDown(evtObj:MouseEvent = null):void{
//trace("onMouseDown();");
var point:Point = new Point(evtObj.localX, evtObj.localY);
point = (evtObj.target as DisplayObject).localToGlobal(point);
if (!listContent.hitTestPoint(point.x, point.y)) {
onMouseUpHandler();
return;
}
// check if mouse press on items
if (mouseEventToItemRenderer(evtObj)) {
onMouseUpHandler();
return;
}
var listPoint:Point = new Point(0, 0);
listPoint = listContent.localToGlobal(listPoint);
point = mouseSelectRect.globalToLocal(point);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
this.addEventListener(ScrollEvent.SCROLL, onScrollHandler);
beginMouseSelect(point);
//dragScroll();
}
protected function onMouseMoveHandler(evtObj:MouseEvent = null):void{
//trace("onMouseMoveHandler();");
var point:Point = new Point(evtObj.localX, evtObj.localY);
point = (evtObj.target as DisplayObject).localToGlobal(point);
point = mouseSelectRect.globalToLocal(point);
updateMouseSelect(point);
//dragScroll();
mouseDragScroll();
}
protected function onMouseUpHandler(evtObj:MouseEvent = null):void{
//trace("onMouseUpHandler();");
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
this.removeEventListener(ScrollEvent.SCROLL, onScrollHandler);
resetMouseDragScrolling();
endMouseSelect();
}
//=================================================================
// Mouse Drag Scroll
//=================================================================
protected function onScrollHandler(evtObj:ScrollEvent):void{
//trace("onScrollHandler();");
updateMouseSelect();
}
protected function resetMouseDragScrolling():void{
if (mouseDragScrollingInterval != 0) {
clearInterval(mouseDragScrollingInterval);
mouseDragScrollingInterval = 0;
}
}
protected function mouseDragScroll():void{
//trace("mouseDragScroll();");
// x 方向快速卷动,会造成 item 显示不正常
var slop:Number = 0;
var scrollInterval:Number;
var oldPosition:Number;
var d:Number;
var scrollEvent:ScrollEvent;
// if (mouseDragScrollingInterval == 0) return;
const minScrollInterval:Number = 30;
clearInterval(mouseDragScrollingInterval);
if (mouseY < slop) {
oldPosition = verticalScrollPosition;
verticalScrollPosition = Math.max(0, oldPosition - 1);
d = Math.min(0 - mouseY - 30, 0);
scrollInterval = 0.593 * d * d + 1 + minScrollInterval;
mouseDragScrollingInterval = setInterval(mouseDragScroll, scrollInterval);
if (oldPosition != verticalScrollPosition) {
scrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
scrollEvent.detail = ScrollEventDetail.THUMB_POSITION;
scrollEvent.direction = ScrollEventDirection.VERTICAL;
scrollEvent.position = verticalScrollPosition;
scrollEvent.delta = verticalScrollPosition - oldPosition;
dispatchEvent(scrollEvent);
}
} else if (mouseY > (unscaledHeight - slop)) {
oldPosition = verticalScrollPosition;
verticalScrollPosition = Math.min(maxVerticalScrollPosition, verticalScrollPosition + 1);
d = Math.min(mouseY - unscaledHeight - 30, 0);
scrollInterval = 0.593 * d * d + 1 + minScrollInterval;
mouseDragScrollingInterval = setInterval(mouseDragScroll, scrollInterval);
if (oldPosition != verticalScrollPosition) {
scrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
scrollEvent.detail = ScrollEventDetail.THUMB_POSITION;
scrollEvent.direction = ScrollEventDirection.VERTICAL;
scrollEvent.position = verticalScrollPosition;
scrollEvent.delta = verticalScrollPosition - oldPosition;
dispatchEvent(scrollEvent);
}
} else if (mouseX < slop) {
oldPosition = horizontalScrollPosition;
horizontalScrollPosition = Math.max(0, oldPosition - 1);
d = Math.min(0 - mouseX - 30, 0);
scrollInterval = 0.593 * d * d + 1 + minScrollInterval;
mouseDragScrollingInterval = setInterval(mouseDragScroll, scrollInterval);
if (oldPosition != horizontalScrollPosition) {
scrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
scrollEvent.detail = ScrollEventDetail.THUMB_POSITION;
scrollEvent.direction = ScrollEventDirection.HORIZONTAL;
scrollEvent.position = horizontalScrollPosition;
scrollEvent.delta = horizontalScrollPosition - oldPosition;
dispatchEvent(scrollEvent);
}
} else if (mouseX > (unscaledWidth - slop)) {
oldPosition = horizontalScrollPosition;
horizontalScrollPosition = Math.min(maxHorizontalScrollPosition, horizontalScrollPosition + 1);
d = Math.min(mouseX - unscaledWidth - 30, 0);
scrollInterval = 0.593 * d * d + 1 + minScrollInterval;
mouseDragScrollingInterval = setInterval(mouseDragScroll, scrollInterval);
if (oldPosition != horizontalScrollPosition) {
scrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
scrollEvent.detail = ScrollEventDetail.THUMB_POSITION;
scrollEvent.direction = ScrollEventDirection.HORIZONTAL;
scrollEvent.position = horizontalScrollPosition;
scrollEvent.delta = horizontalScrollPosition - oldPosition;
dispatchEvent(scrollEvent);
}
} else {
mouseDragScrollingInterval = setInterval(mouseDragScroll, 15);
}
}
/*//
// override ListBase.dragScroll()
protected override function dragScroll():void {
trace("dragScroll();");
trace("DragManager.isDragging : " + DragManager.isDragging);
super.dragScroll();
//trace("collection : " + collection);
//trace((mouseY > unscaledHeight));
var slop:Number = 0;
}
//*/
/*/
protected override function mouseMoveHandler(event:MouseEvent):void{
trace("mouseMoveHandler();");
}
//*/
//=================================================================
//
//=================================================================
protected function beginMouseSelect(point:Point):void{
//trace("beginMouseSelect();", point);
//adjustPoint(point);
if (ctrlKey || shiftKey) {
this.oldSelectedIndices = [];
} else {
this.selectedIndices = [];
this.oldSelectedIndices = [];
}
endIndexPoint = startIndexPoint = pointToIndex(point);
point.x += this.horizontalScrollPosition * this.columnWidth;
point.y += this.verticalScrollPosition * this.rowHeight;
endPoint = startPoint = point;
drawMouseSelectRect();
}
protected function updateMouseSelect(point:Point = null):void{
//trace("updateMouseSelect();");
//adjustPoint(point);
if (!point) {
point = new Point(mouseSelectRect.mouseX, mouseSelectRect.mouseY);
}
endIndexPoint = pointToIndex(point);
point.x += this.horizontalScrollPosition * this.columnWidth;
point.y += this.verticalScrollPosition * this.rowHeight;
endPoint = point;
drawMouseSelectRect();
//trace(startIndexPoint, endIndexPoint);
var newSelectedIndices:Array = [];
var i:Number, ix:Number, iy:Number;
if (this.direction == TileBaseDirection.HORIZONTAL) {
for (i = 0 ; i < dataProvider.length ; ++i) {
ix = i % this.columnCount;
iy = Math.floor(i / this.columnCount);
xFlag = false;
if (startIndexPoint.x <= endIndexPoint.x) {
xFlag = ix >= startIndexPoint.x && ix <= endIndexPoint.x;
} else {
xFlag = ix <= startIndexPoint.x && ix >= endIndexPoint.x;
}
yFlag = false;
if (startIndexPoint.y <= endIndexPoint.y) {
yFlag = iy >= startIndexPoint.y && iy <= endIndexPoint.y;
} else {
yFlag = iy <= startIndexPoint.y && iy >= endIndexPoint.y;
}
if (xFlag && yFlag) {
newSelectedIndices.push(i);
}
}
} else {
for (i = 0 ; i < dataProvider.length ; ++i) {
ix = Math.floor(i / this.rowCount);
iy = i % this.rowCount;
xFlag = false;
if (startIndexPoint.x <= endIndexPoint.x) {
xFlag = ix >= startIndexPoint.x && ix <= endIndexPoint.x;
} else {
xFlag = ix <= startIndexPoint.x && ix >= endIndexPoint.x;
}
yFlag = false;
if (startIndexPoint.y <= endIndexPoint.y) {
yFlag = iy >= startIndexPoint.y && iy <= endIndexPoint.y;
} else {
yFlag = iy <= startIndexPoint.y && iy >= endIndexPoint.y;
}
if (xFlag && yFlag) {
newSelectedIndices.push(i);
}
}
}
var xFlag:Boolean = false;
var yFlag:Boolean = false;
var deltaDict:Dictionary = new Dictionary();
var o:*;
var selectedIndices:Array;
//var oldSelectedIndices:Array = this.selectedIndices;
// Update selectedIndices
if (this.ctrlKey) {
var index:Number;
for (i = 0 ; i < oldSelectedIndices.length ; ++i) {
index = oldSelectedIndices[i];
deltaDict[index] = null;
}
oldSelectedIndices = newSelectedIndices;
for (i = 0 ; i < newSelectedIndices.length ; ++i) {
index = newSelectedIndices[i];
if (index in deltaDict) {
delete deltaDict[index];
} else {
deltaDict[index] = null;
}
}
selectedIndices = this.selectedIndices;
for (i = 0 ; i < selectedIndices.length ; ++i) {
index = selectedIndices[i];
if (index in deltaDict) {
delete deltaDict[index];
} else {
deltaDict[index] = null;
}
}
newSelectedIndices = [];
for (o in deltaDict) { newSelectedIndices.push(o); }
} else if (this.shiftKey) {
var deltaAddDict:Dictionary = new Dictionary();
var deltaRemoveDict:Dictionary = new Dictionary();
for (i = 0 ; i < oldSelectedIndices.length ; ++i) {
deltaRemoveDict[oldSelectedIndices[i]] = null;
}
for (i = 0 ; i < newSelectedIndices.length ; ++i) {
index = newSelectedIndices[i];
deltaAddDict[index] = null;
if (index in deltaRemoveDict) {
delete deltaRemoveDict[index];
}
}
oldSelectedIndices = newSelectedIndices;
selectedIndices = this.selectedIndices;
for (i = 0 ; i < selectedIndices.length ; ++i) {
deltaDict[selectedIndices[i]] = null;
}
for (o in deltaAddDict) { deltaDict[o] = null; }
for (o in deltaRemoveDict) { delete deltaDict[o]; }
newSelectedIndices = [];
for (o in deltaDict) { newSelectedIndices.push(o); }
} else {
selectedIndices = this.selectedIndices;
this.oldSelectedIndices = newSelectedIndices.concat();
}
// Check if selectedIndicesupdated
outer: if (selectedIndices.length == newSelectedIndices.length) {
selectedIndices.sort(Array.NUMERIC);
newSelectedIndices.sort(Array.NUMERIC);
for (i = 0 ; i < selectedIndices.length ; ++i) {
if (newSelectedIndices[i] != selectedIndices[i]) {
break outer;
}
}
return;
}
newSelectedIndices.reverse();
this.selectedIndices = newSelectedIndices;
}
protected function endMouseSelect():void{
//trace("endMouseSelect();");
var g:Graphics = mouseSelectRect.graphics;
g.clear();
var evt:ListEvent = new ListEvent(ListEvent.CHANGE);
dispatchEvent(evt);
}
//=================================================================
//
//=================================================================
protected function drawMouseSelectRect():void{
var drawStartPoint:Point = new Point();
var drawEndPoint:Point = new Point();
drawStartPoint.x = this.startPoint.x - this.horizontalScrollPosition * this.columnWidth;
drawStartPoint.y = this.startPoint.y - this.verticalScrollPosition * this.rowHeight;
drawEndPoint.x = this.endPoint.x - this.horizontalScrollPosition * this.columnWidth;
drawEndPoint.y = this.endPoint.y - this.verticalScrollPosition * this.rowHeight;
var adjustDrawStartPoint:Point = adjustPoint(drawStartPoint);
var adjustDrawEndPoint:Point = adjustPoint(drawEndPoint);
var g:Graphics = mouseSelectRect.graphics;
g.clear();
g.lineStyle(1, 0x0, 0.5, true);
g.moveTo(adjustDrawStartPoint.x, adjustDrawStartPoint.y);
if (drawStartPoint.y >= 0 && drawStartPoint.y <= listContent.height) {
g.lineTo(adjustDrawEndPoint.x, adjustDrawStartPoint.y);
}
g.moveTo(adjustDrawEndPoint.x, adjustDrawStartPoint.y);
g.lineTo(adjustDrawEndPoint.x, adjustDrawEndPoint.y);
g.moveTo(adjustDrawEndPoint.x, adjustDrawEndPoint.y);
g.lineTo(adjustDrawStartPoint.x, adjustDrawEndPoint.y);
g.moveTo(adjustDrawStartPoint.x, adjustDrawEndPoint.y);
if (drawStartPoint.x >= 0 && drawStartPoint.x <= listContent.width) {
g.lineTo(adjustDrawStartPoint.x, adjustDrawStartPoint.y);
}
g.moveTo(adjustDrawStartPoint.x, adjustDrawStartPoint.y);
//*/
g.lineStyle(0, 0x0, 0, true);
g.beginFill(0x0000FF, 0.1);
g.drawRect(adjustDrawStartPoint.x, adjustDrawStartPoint.y,
adjustDrawEndPoint.x - adjustDrawStartPoint.x, adjustDrawEndPoint.y - adjustDrawStartPoint.y);
g.endFill();
//*/
}
//=================================================================
//
//=================================================================
protected function adjustPoint(p:Point):Point{
var newPoint:Point = new Point();
newPoint.x = p.x < 0 ? 0 : p.x;
newPoint.y = p.y < 0 ? 0 : p.y;
newPoint.x = newPoint.x > listContent.width - 1 ? listContent.width - 1 : newPoint.x;
newPoint.y = newPoint.y > listContent.height - 1 ? listContent.height - 1 : newPoint.y;
return newPoint;
}
protected function pointToIndex(p:Point):Point{
var indexPoint:Point = new Point();
indexPoint.x = Math.floor(p.x / this.columnWidth) + this.horizontalScrollPosition - 0.5;
indexPoint.y = Math.floor(p.y / this.rowHeight) + this.verticalScrollPosition - 0.5;
//*/
indexPoint.x += (p.x % this.columnWidth) > itemMargin ? 0.5 : 0;
indexPoint.y += (p.y % this.rowHeight) > itemMargin ? 0.5 : 0;
indexPoint.x += (p.x % this.columnWidth) > (this.columnWidth - itemMargin) ? 0.5 : 0;
indexPoint.y += (p.y % this.rowHeight) > (this.rowHeight - itemMargin) ? 0.5 : 0;
//*/
return indexPoint;
}
//=================================================================
// Override TileBase Functions
//=================================================================
override protected function updateDisplayList
(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
//this.addChildAt(mouseSelectRect, this.numChildren);
//this.addChild(mouseSelectRect);
mouseSelectRect.x = listContent.x;
mouseSelectRect.y = listContent.y;
//this.listContent.visible = false;
}
override protected function makeRowsAndColumns(left:Number, top:Number,
right:Number, bottom:Number,
firstCol:int, firstRow:int,
byCount:Boolean = false, rowsNeeded:uint = 0):Point {
//trace(this, "makeRowsAndColumns " + left + " " + top + " " + right + " " + bottom + " " + firstCol + " " + firstRow);
var numRows:int;
var numCols:int;
var colNum:int;
var rowNum:int;
var xx:Number;
var yy:Number;
var wrappedData:Object;
var data:Object;
var uid:String
var oldItem:IListItemRenderer
var item:IListItemRenderer;
var more:Boolean;
var valid:Boolean;
var i:int;
var rh:Number;
var lastRowMade:int;
var lastColumnMade:int;
var bSelected:Boolean = false;
var bHighlight:Boolean = false;
var bCaret:Boolean = false;
// trace("TileBase.makeRowsAndColumns, horizontalScrollPosition = " + horizontalScrollPosition +
// ", iterator index = " + iterator.bookmark.getViewIndex() + ", iterator current = " +
// iterator.current);
if (columnWidth == 0 || rowHeight == 0)
return null;
invalidateSizeFlag = true;
allowItemSizeChangeNotification = false;
if (direction == TileBaseDirection.VERTICAL) {
numRows = maxRows > 0 ? maxRows : Math.max(Math.floor(listContent.heightExcludingOffsets / rowHeight), 1);
numCols = Math.max(Math.ceil((listContent.widthExcludingOffsets)/ columnWidth), 1);
setRowCount(numRows);
setColumnCount(numCols);
colNum = firstCol;
xx = left;
lastColumnMade = colNum - 1;
more = (iterator != null && !iterator.afterLast && iteratorValid);
while ((byCount && rowsNeeded--) || (!byCount && (colNum < numCols + firstCol))) {
rowNum = firstRow;
yy = top;
while (rowNum < numRows) {
valid = more;
wrappedData = more ? iterator.current : null;
data = (wrappedData is ItemWrapper) ? wrappedData.data : wrappedData;
more = moveNextSafely(more);
if (!listItems[rowNum])
listItems[rowNum] = [];
if (valid && yy < bottom) {
uid = itemToUID(wrappedData);
rowInfo[rowNum] = new ListRowInfo(yy, rowHeight, uid);
item = getPreparedItemRenderer(rowNum, colNum, wrappedData, data, uid);
placeAndDrawItemRenderer(item,xx,yy,uid);
lastColumnMade = Math.max(colNum,lastColumnMade);
} else {
oldItem = listItems[rowNum][colNum];
if (oldItem) {
addToFreeItemRenderers(oldItem);
listContent.removeChild(DisplayObject(oldItem));
// delete rowMap[oldItem.name];
listItems[rowNum][colNum] = null;
}
rowInfo[rowNum] = new ListRowInfo(yy, rowHeight, uid);
}
yy += rowHeight;
rowNum++;
}
colNum ++;
if (firstRow) {
// we're doing a row along the bottom so we have to skip the beginning of the next column
for (i = 0; i < firstRow; i++)
more = moveNextSafely(more);
}
xx += columnWidth;
}
} else { // horizontal
numCols = maxColumns > 0 ? maxColumns : Math.max(Math.floor((listContent.widthExcludingOffsets)/ columnWidth), 1);
numRows = Math.max(Math.ceil(listContent.heightExcludingOffsets / rowHeight), 1);
setColumnCount(numCols);
setRowCount(numRows);
rowNum = firstRow;
yy = top;
more = (iterator != null && !iterator.afterLast && iteratorValid);
lastRowMade = rowNum-1;
while ((byCount && rowsNeeded--) || (!byCount && rowNum < numRows + firstRow)) {
colNum = firstCol;
xx = left;
rowInfo[rowNum] = null;
while (colNum < numCols) {
valid = more;
wrappedData = more ? iterator.current : null;
data = (wrappedData is ItemWrapper) ? wrappedData.data : wrappedData;
more = moveNextSafely(more);
if (!listItems[rowNum])
listItems[rowNum] = [];
if (valid && xx < right) {
uid = itemToUID(wrappedData);
if (!rowInfo[rowNum])
rowInfo[rowNum] = new ListRowInfo(yy, rowHeight, uid);
item = getPreparedItemRenderer(rowNum, colNum, wrappedData, data, uid);
placeAndDrawItemRenderer(item,xx,yy,uid);
lastRowMade = rowNum;
} else {
if (!rowInfo[rowNum])
rowInfo[rowNum] = new ListRowInfo(yy, rowHeight, uid);
oldItem = listItems[rowNum][colNum];
if (oldItem) {
addToFreeItemRenderers(oldItem);
listContent.removeChild(DisplayObject(oldItem));
listItems[rowNum][colNum] = null;
}
}
xx += columnWidth;
colNum++;
}
rowNum ++;
if (firstCol) {
// we're doing a column along the side so we have to skip the beginning of the next column
for (i = 0; i < firstCol; i++)
more = moveNextSafely(more);
}
yy += rowHeight;
}
}
if (!byCount) {
var a:Array;
// prune excess rows and columns
while (listItems.length > numRows + offscreenExtraRowsTop) {
a = listItems.pop();
rowInfo.pop();
for (i = 0; i < a.length; i++) {
oldItem = a[i];
if (oldItem) {
if (oldItem.parent)
listContent.removeChild(DisplayObject(oldItem));
addToFreeItemRenderers(oldItem);
}
}
}
if (listItems.length && listItems[0].length > numCols + offscreenExtraColumnsLeft) {
for (i = 0; i < numRows + offscreenExtraRowsTop; i++) {
a = listItems[i];
while (a.length > numCols + offscreenExtraColumnsLeft) {
oldItem = a.pop();
if (oldItem) {
if (oldItem.parent)
listContent.removeChild(DisplayObject(oldItem));
addToFreeItemRenderers(oldItem);
}
}
}
}
}
allowItemSizeChangeNotification = true;
invalidateSizeFlag = false;
return new Point(lastColumnMade - firstCol + 1,lastRowMade - firstRow + 1);
}
private function moveNextSafely(more:Boolean):Boolean {
if (iterator && more) {
try {
more = iterator.moveNext();
}
catch(e1:ItemPendingError) {
lastSeekPending = new ListBaseSeekPending(CursorBookmark.CURRENT, 0);
e1.addResponder(new ItemResponder(seekPendingResultHandler, seekPendingFailureHandler,
lastSeekPending));
more = false;
iteratorValid = false;
}
}
return more;
}
private function getPreparedItemRenderer(rowNum:int,colNum:int, wrappedData:Object,
data:Object, uid:String):IListItemRenderer {
var oldItem:IListItemRenderer = listItems[rowNum][colNum];
var item:IListItemRenderer;
var rowData:ListData;
if (oldItem) {
// If we're running a data effect, do a more expensive check when
// determining if we can reuse this item renderer
if (runningDataEffect ? (dataItemWrappersByRenderer[oldItem] != wrappedData) : (oldItem.data != data))
addToFreeItemRenderers(oldItem);
else
item = oldItem;
}
if (!item) {
// if we're allowed to re-use existing renderers
if (allowRendererStealingDuringLayout) {
// try to steal item renderer if it already exists,
// but don't steal item renderers that have already
// been used in the layout. (This will happen if there
// are duplicate UIDs in the collection, which shouldn't
// really happen, but nevertheless may happen).
item = visibleData[uid];
// if we can't steal an item based on it's UID,
// steal based on the UID of the underlying data
if (!item && (wrappedData != data))
item = visibleData[itemToUID(data)];
}
// if we've stolen a renderer from somewhere else...
if (item) {
// update data structures so we're not pointing to it twice
var ld:ListData = ListData(rowMap[item.name]);
if (ld) {
if (((direction == TileBaseDirection.HORIZONTAL) &&
((ld.rowIndex > rowNum) || ((ld.rowIndex == rowNum) && (ld.columnIndex > colNum)))) ||
((direction == TileBaseDirection.VERTICAL) &&
((ld.columnIndex > colNum) || ((ld.columnIndex == colNum) && (ld.rowIndex > rowNum)))))
listItems[ld.rowIndex][ld.columnIndex] = null;
else
item = null;
}
}
if (!item) {
item = getReservedOrFreeItemRenderer(wrappedData);
if (item && !isRendererUnconstrained(item)) {
item.x = 0;
item.y = 0;
}
}
// if all else fails...
if (!item)
item = createItemRenderer(data);
item.owner = this;
item.styleName = listContent;
item.visible = true;
}
rowData = ListData(makeListData(data, uid, rowNum, colNum));
rowMap[item.name] = rowData;
if (item is IDropInListItemRenderer)
IDropInListItemRenderer(item).listData = data ? rowData : null;
item.data = data;
if (wrappedData != data)
dataItemWrappersByRenderer[item] = wrappedData;
if (!item.parent)
listContent.addChild(DisplayObject(item));
item.visible = true;
if (uid)
visibleData[uid] = item;
listItems[rowNum][colNum] = item;
UIComponentGlobals.layoutManager.validateClient(item, true);
return item;
}
private function placeAndDrawItemRenderer(item:IListItemRenderer, xx:Number, yy:Number, uid:String):void {
var bSelected:Boolean = false;
var bHighlight:Boolean = false;
var bCaret:Boolean = false;
var rh:Number;
rh = item.getExplicitOrMeasuredHeight();
if (item.width != columnWidth - itemMargin * 2 || rh != (rowHeight - cachedPaddingTop - cachedPaddingBottom - itemMargin * 2))
item.setActualSize(columnWidth - itemMargin * 2, rowHeight - cachedPaddingTop - cachedPaddingBottom - itemMargin * 2);
// this is not really doing anything yet
if (!isRendererUnconstrained(item))
item.move(xx + itemMargin, yy + cachedPaddingTop + itemMargin);
bSelected = selectedData[uid] != null;
if (runningDataEffect) {
bSelected = bSelected || (selectedData[itemToUID(item.data)] != null);
bSelected = bSelected && (!getRendererSemanticValue(item,ModifiedCollectionView.REPLACEMENT))
&& (!getRendererSemanticValue(item,ModifiedCollectionView.ADDED));
}
bHighlight = highlightUID == uid;
bCaret = caretUID == uid;
if (uid)
drawItem(item, bSelected, bHighlight, bCaret);
}
//=================================================================
// Override ListBase Functions
//=================================================================
//*/
override mx_internal function mouseEventToItemRendererOrEditor(
event:MouseEvent):IListItemRenderer {
var target:DisplayObject = DisplayObject(event.target);
if (target == listContent) {
var pt:Point = new Point(event.stageX, event.stageY);
pt = listContent.globalToLocal(pt);
if (pt.y % rowHeight < itemMargin || pt.y % rowHeight > columnWidth - itemMargin) {
return null;
}
if (pt.x % columnWidth < itemMargin || pt.x % columnWidth > columnWidth - itemMargin) {
return null;
}
var yy:Number = 0;
var n:int = listItems.length;
for (var i:int = 0; i < n; i++) {
if (listItems[i].length) {
if (pt.y < yy + rowInfo[i].height) {
var m:int = listItems[i].length;
// if (m == 1) return listItems[i][0];
var j:int = Math.floor(pt.x / columnWidth);
return listItems[i][j];
}
}
yy += rowInfo[i].height;
}
} else if (target == highlightIndicator) {
return lastHighlightItemRenderer;
}
while (target && target != this) {
if (target is IListItemRenderer && target.parent == listContent) {
if (target.visible)
return IListItemRenderer(target);
break;
}
if (target is IUIComponent)
target = IUIComponent(target).owner;
else
target = target.parent;
}
return null;
}
//*/
//=================================================================
// Overide ListBase draw Functions
//=================================================================
override protected function drawSelectionIndicator(
indicator:Sprite, x:Number, y:Number,
width:Number, height:Number, color:uint,
itemRenderer:IListItemRenderer):void {
/*/
super.drawSelectionIndicator(
indicator, x, y + itemMargin,
width, height - itemMargin * 2,
color, itemRenderer);
//*/
var g:Graphics = Sprite(indicator).graphics;
g.clear();
g.beginFill(color, 0.5);
g.drawRoundRect(0, 0, width, height - itemMargin * 2, 20, 20);
g.endFill();
indicator.x = x;
indicator.y = y + itemMargin;
}
override protected function drawHighlightIndicator(
indicator:Sprite, x:Number, y:Number,
width:Number, height:Number, color:uint,
itemRenderer:IListItemRenderer):void {
/*/
super.drawSelectionIndicator(
indicator, x, y + itemMargin,
width, height - itemMargin * 2,
color, itemRenderer);
//*/
var g:Graphics = Sprite(indicator).graphics;
g.clear();
g.beginFill(color, 0.5);
g.drawRoundRect(0, 0, width, height - itemMargin * 2, 20, 20);
g.endFill();
indicator.x = x;
indicator.y = y + itemMargin;
}
override protected function drawCaretIndicator(
indicator:Sprite, x:Number, y:Number,
width:Number, height:Number, color:uint,
itemRenderer:IListItemRenderer):void {
/*/
super.drawSelectionIndicator(
indicator, x, y + itemMargin,
width, height - itemMargin * 2,
color, itemRenderer);
//*/
var g:Graphics = Sprite(indicator).graphics;
g.clear();
g.lineStyle(2, color, 1, true);
g.drawRoundRect(0, 0, width, height - itemMargin * 2, 20, 20);
indicator.x = x;
indicator.y = y + itemMargin;
}
}
}
Online Demo:
相关连结:
Flex 2 - 实作鼠标可圈选的 TileList
Flex 2 - 实作鼠标可圈选的 TileList V2