blob: 0ea2aac9bb6c3dd6a9a74f6b11c445bdbc72d25c [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package spark.components.supportClasses
{
import flash.geom.PerspectiveProjection;
import flash.geom.Rectangle;
import flash.display.DisplayObject;
import mx.core.IFactory;
import mx.core.IVisualElement;
import mx.utils.MatrixUtil;
import spark.components.DataGroup;
import spark.components.Group;
import spark.components.IItemRenderer;
import spark.components.List;
/**
* The ListItemDragProxy class defines the default drag proxy used
* when dragging from a Spark List based control.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public class ListItemDragProxy extends Group
{
include "../../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function ListItemDragProxy()
{
super();
}
//--------------------------------------------------------------------------
//
// Overridden methods: UIComponent
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function createChildren():void
{
super.createChildren();
var list:List = owner as List;
if (!list)
return;
var dataGroup:DataGroup = list.dataGroup;
if (!dataGroup)
return;
// Make sure we inherit styles from the drag initiator, as those styles
// may be affecting the appearance of the item renderers.
this.styleName = list;
width = dataGroup.width
height = dataGroup.height;
// Find all visible children within the selection:
var selection:Vector.<int> = list.selectedIndices;
if (!selection)
return;
var offsetX:Number = 0;
var offsetY:Number = 0;
var scrollRect:Rectangle = dataGroup.scrollRect;
if (scrollRect)
{
offsetX = scrollRect.x;
offsetY = scrollRect.y;
}
var perspectiveProjection:PerspectiveProjection = dataGroup.transform.perspectiveProjection;
// Construct an image by adding clones of the visible item renderers
var elementsIn3D:Boolean = false;
var count:int = selection.length;
for (var i:int = 0; i < count; i++)
{
// The element may be null if the layout is virtualized and the
// ItemRenderer is not created by the layout (usually when the
// ItemRenderer falls outside the viewport).
var element:IVisualElement = dataGroup.getElementAt(selection[i]);
if (!element || !(element is IItemRenderer))
continue;
if (element.is3D)
elementsIn3D = true;
// Check visibility of the ItemRenderer. It's not guaranteed that the
// dataGroup returns null for ItemRenderers outside the viewport
if (scrollRect)
{
var elementBounds:Rectangle;
if (element.hasLayoutMatrix3D)
{
// Bounds in child coordinates
elementBounds = new Rectangle(0, 0,
element.getLayoutBoundsWidth(false),
element.getLayoutBoundsHeight(false));
// Bounds transformed in 3D and projected to parent
elementBounds = MatrixUtil.projectBounds(elementBounds,
element.getLayoutMatrix3D(),
perspectiveProjection);
}
else
elementBounds = getElementBounds(element);
if (!scrollRect.containsRect(elementBounds) && !scrollRect.intersects(elementBounds))
continue;
}
var clone:IItemRenderer = cloneItemRenderer(IItemRenderer(element), list);
// Copy the dimensions
clone.width = element.width;
clone.height = element.height;
// Copy the transform
if (element.hasLayoutMatrix3D)
clone.setLayoutMatrix3D(element.getLayoutMatrix3D(), false);
else
clone.setLayoutMatrix(element.getLayoutMatrix(), false);
clone.x -= offsetX;
clone.y -= offsetY;
// Copy other relevant properties
clone.depth = element.depth;
clone.visible = element.visible;
if (element.postLayoutTransformOffsets)
clone.postLayoutTransformOffsets = element.postLayoutTransformOffsets;
// Put it in a dragging state
clone.dragging = true;
// Add the clone as a child
addElement(clone);
}
// Copy projection matrix, if there was an element in 3d.
if (elementsIn3D)
this.transform.perspectiveProjection = perspectiveProjection;
}
//--------------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------------
// TODO (egeorgie): find a better place for this helper method.
static private var elementBounds:Rectangle;
/**
* @private
* Returns the bounds for the passed in element.
*/
private function getElementBounds(element:IVisualElement):Rectangle
{
if (!elementBounds)
elementBounds = new Rectangle();
elementBounds.x = element.getLayoutBoundsX();
elementBounds.y = element.getLayoutBoundsY();
elementBounds.width = element.getLayoutBoundsWidth();
elementBounds.height = element.getLayoutBoundsHeight();
return elementBounds;
}
/**
* @private
* Clones the passed in renderer. The data item is not cloned.
* The clone and the original render the same item.
*/
private function cloneItemRenderer(renderer:IItemRenderer, list:List):IItemRenderer
{
// Create a new ItemRenderer:
// 1. if itemRendererFunction is defined, call it to get the renderer factory and instantiate it
// 2. if itemRenderer is defined, instantiate one
// 1. if itemRendererFunction is defined, call it to get the renderer factory and instantiate it
var rendererFactory:IFactory;
var itemRendererFunction:Function = list.itemRendererFunction;
var data:Object = renderer.data;
if (itemRendererFunction != null)
rendererFactory = itemRendererFunction(data);
// 2. if itemRenderer is defined, instantiate one
if (!rendererFactory)
rendererFactory = list.itemRenderer;
var newRenderer:IItemRenderer = rendererFactory.newInstance();
// Initialize the item renderer
if (!newRenderer)
return null;
// The list is the IItemRendererOwner for this renderer.
// It will set all the properties on this renderer, based on
// the itemIndex and data.
list.updateRenderer(newRenderer, renderer.itemIndex, data);
return newRenderer;
}
}
}