// =================================================================================================
//
// Starling Framework
// Copyright 2011 Gamua OG. All Rights Reserved.
//
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================
package starling.display
{
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getQualifiedClassName;
import starling.core.RenderSupport;
import starling.errors.AbstractClassError;
import starling.events.Event;
import starling.utils.transformCoords;
/**
* A DisplayObjectContainer represents a collection of display objects.
* It is the base class of all display objects that act as a container for other objects. By
* maintaining an ordered list of children, it defines the back-to-front positioning of the
* children within the display tree.
*
*
A container does not a have size in itself. The width and height properties represent the
* extents of its children. Changing those properties will scale all children accordingly.
*
* As this is an abstract class, you can't instantiate it directly, but have to
* use a subclass instead. The most lightweight container class is "Sprite".
*
* Adding and removing children
*
* The class defines methods that allow you to add or remove children. When you add a child,
* it will be added at the frontmost position, possibly occluding a child that was added
* before. You can access the children via an index. The first child will have index 0, the
* second child index 1, etc.
*
* Adding and removing objects from a container triggers non-bubbling events.
*
*
* Event.ADDED: the object was added to a parent.
* Event.ADDED_TO_STAGE: the object was added to a parent that is
* connected to the stage, thus becoming visible now.
* Event.REMOVED: the object was removed from a parent.
* Event.REMOVED_FROM_STAGE: the object was removed from a parent that
* is connected to the stage, thus becoming invisible now.
*
*
* Especially the ADDED_TO_STAGE event is very helpful, as it allows you to
* automatically execute some logic (e.g. start an animation) when an object is rendered the
* first time.
*
* @see Sprite
* @see DisplayObject
*/
public class DisplayObjectContainer extends DisplayObject
{
// members
private var mChildren:Vector.;
/** Helper objects. */
private static var sHelperMatrix:Matrix = new Matrix();
private static var sHelperPoint:Point = new Point();
// construction
/** @private */
public function DisplayObjectContainer()
{
if (getQualifiedClassName(this) == "starling.display::DisplayObjectContainer")
throw new AbstractClassError();
mChildren = new [];
}
/** Disposes the resources of all children. */
public override function dispose():void
{
var numChildren:int = mChildren.length;
for (var i:int=0; i= 0 && index <= numChildren)
{
child.removeFromParent();
mChildren.splice(index, 0, child);
child.setParent(this);
child.dispatchEvent(new Event(Event.ADDED, true));
if (stage) child.dispatchEventOnChildren(new Event(Event.ADDED_TO_STAGE));
}
else
{
throw new RangeError("Invalid child index");
}
}
/** Removes a child from the container. If the object is not a child, nothing happens.
* If requested, the child will be disposed right away. */
public function removeChild(child:DisplayObject, dispose:Boolean=false):void
{
var childIndex:int = getChildIndex(child);
if (childIndex != -1) removeChildAt(childIndex, dispose);
}
/** Removes a child at a certain index. Children above the child will move down. If
* requested, the child will be disposed right away. */
public function removeChildAt(index:int, dispose:Boolean=false):void
{
if (index >= 0 && index < numChildren)
{
var child:DisplayObject = mChildren[index];
child.dispatchEvent(new Event(Event.REMOVED, true));
if (stage) child.dispatchEventOnChildren(new Event(Event.REMOVED_FROM_STAGE));
child.setParent(null);
mChildren.splice(index, 1);
if (dispose) child.dispose();
}
else
{
throw new RangeError("Invalid child index");
}
}
/** Removes a range of children from the container (endIndex included).
* If no arguments are given, all children will be removed. */
public function removeChildren(beginIndex:int=0, endIndex:int=-1, dispose:Boolean=false):void
{
if (endIndex < 0 || endIndex >= numChildren)
endIndex = numChildren - 1;
for (var i:int=beginIndex; i<=endIndex; ++i)
removeChildAt(beginIndex, dispose);
}
/** Returns a child object at a certain index. */
public function getChildAt(index:int):DisplayObject
{
if (index >= 0 && index < numChildren)
return mChildren[index];
else
throw new RangeError("Invalid child index");
}
/** Returns a child object with a certain name (non-recursively). */
public function getChildByName(name:String):DisplayObject
{
var numChildren:int = mChildren.length;
for (var i:int=0; i resultRect.right ? maxX : resultRect.right;
minY = minY < resultRect.y ? minY : resultRect.y;
maxY = maxY > resultRect.bottom ? maxY : resultRect.bottom;
}
resultRect.x = minX;
resultRect.y = minY;
resultRect.width = maxX - minX;
resultRect.height = maxY - minY;
return resultRect;
}
}
/** @inheritDoc */
public override function hitTest(localPoint:Point, forTouch:Boolean=false):DisplayObject
{
if (forTouch && (!visible || !touchable))
return null;
var localX:Number = localPoint.x;
var localY:Number = localPoint.y;
var numChildren:int = mChildren.length;
for (var i:int=numChildren-1; i>=0; --i) // front to back!
{
var child:DisplayObject = mChildren[i];
getTransformationMatrix(child, sHelperMatrix);
transformCoords(sHelperMatrix, localX, localY, sHelperPoint);
var target:DisplayObject = child.hitTest(sHelperPoint, forTouch);
if (target) return target;
}
return null;
}
/** @inheritDoc */
public override function render(support:RenderSupport, alpha:Number):void
{
alpha *= this.alpha;
var numChildren:int = mChildren.length;
for (var i:int=0; i = new [];
getChildEventListeners(this, event.type, listeners);
var numListeners:int = listeners.length;
for (var i:int=0; i):void
{
var container:DisplayObjectContainer = object as DisplayObjectContainer;
if (object.hasEventListener(eventType))
listeners.push(object);
if (container)
{
var children:Vector. = container.mChildren;
var numChildren:int = children.length;
for (var i:int=0; i