// ================================================================================================= // // 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. * * * * 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