/** * com.voidelement.manager.DepthManager Class for ActionScript 3.0 * * @author Copyright (c) 2007 munegon * @version 1.0 * * @link http://www.voidelement.com/ * @link http://void.heteml.jp/blog/ * * Licensed 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 com.voidelement.manager { import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.utils.Dictionary; public class DepthManager { private const DEPTH_RESERVED:int = 1048575; private const DEPTH_HIGHEST :int = 2130690045; private const DEPTH_LOWEST :int = -16383; private var _container:DisplayObjectContainer; private var _dict:Dictionary; /** * コンストラクタ * * @param base 進度を管理するDisplayObjectContainer */ public function DepthManager( container:DisplayObjectContainer ):void { _container = container; _dict = new Dictionary( true ); var len:int = _container.numChildren; var child:DisplayObject; for ( var i:int = 0; i < len; ++i ){ child = _container.getChildAt( i ); _dict[ i ] = child; _dict[ child ] = i; } } /** * 末尾に子を追加する * * @param child 追加するDisplayObject */ public function addChild( child:DisplayObject ):DisplayObject { var depth:int = _container.numChildren ? _dict[ _container.getChildAt( _container.numChildren - 1 ) ] + 1 : 0; _dict[ depth ] = child; _dict[ child ] = depth; return _container.addChild( child ); } /** * 指定した深度に子を追加する * * @param child 追加するDisplayObject * @param depth 追加先深度 */ public function addChildAt( child:DisplayObject, depth:int ):DisplayObject { var index:int = searchIndex( depth ); if ( index < _container.numChildren ){ var child0:DisplayObject = _container.getChildAt( index ); if ( _dict[ child0 ] == depth ){ // 指定深度に先客がいる場合は削除 removeChild( child0 ); } } _dict[ depth ] = child; _dict[ child ] = depth; return _container.addChildAt( child, index ); } /** * 指定した深度へ子を移動させる * * @param child 移動するDisplayObject * @param depth 移動先深度 */ public function setDepth( child:DisplayObject, depth:int ):void { if ( ( depth < DEPTH_LOWEST ) || ( depth > DEPTH_HIGHEST ) ){ throw( new Error("Caution: " + depth + " is over limit of depth") ); } if ( _dict[ child ] == depth ){ return; } var child0:DisplayObject = getInstanceAtDepth( depth ); if ( child0 != null ){ // 指定深度に先客がいる場合は交換 swapChildren( child, child0 ); } else { var index:int = searchIndex( depth ); delete _dict[ _dict[ child ] ]; _dict[ child ] = depth; _dict[ depth ] = child; if ( _container.getChildIndex( child ) < index ){ _container.setChildIndex( child, index - 1 ); } else { _container.setChildIndex( child, index ); } } } /** * 指定した子の深度を取得する */ public function getDepth( child:DisplayObject ):int { return _dict[ child ]; } /** * 子を交換する */ public function swapChildren( child1:DisplayObject, child2:DisplayObject ):void { if ( child1 == child2 ){ return; } var depth:int = _dict[ child1 ]; _dict[ child1 ] = _dict[ child2 ]; _dict[ child2 ] = depth; _dict[ _dict[ child1 ] ] = child1; _dict[ _dict[ child2 ] ] = child2; _container.swapChildren( child1, child2 ); } /** * 指定した子を削除する * * @param child 削除するDisplayObject */ public function removeChild( child:DisplayObject ):DisplayObject { delete _dict[ _dict[ child ] ]; delete _dict[ child ]; return _container.removeChild( child ); } /** * 指定深度の子を削除する * * @param depth 削除指定深度 */ public function removeChildAt( depth:int ):DisplayObject { var child:DisplayObject = _dict[ depth ]; if ( child == null ){ throw( new RangeError("Caution: no child at depth " + depth ) ); } delete _dict[ child ]; delete _dict[ depth ]; return _container.removeChild( child ); } /** * 指定深度に該当する子のインデックスを返す */ private function searchIndex( depth:int ):int { if ( _container.numChildren > 0 ){ var left:int = 0; var right:int = _container.numChildren - 1; var index:int = right; var child:DisplayObject = _container.getChildAt( index ); if ( depth <= _dict[ _container.getChildAt( 0 ) ] ){ return 0; } if ( _dict[ child ] < depth ){ return index + 1; } while ( _dict[ child ] != depth ){ if ( index == left ){ index += ( _dict[ child ] < depth ) ? 1 : 0; break; } else if ( depth < _dict[ child ] ){ right = index; index = ( left + right ) >> 1; } else if ( _dict[ child ] < depth ){ left = index; index = ( left + right ) >> 1; } else { break; } child = _container.getChildAt( index ); } return index; } else { return 0; } } /** * 指定深度に配置されているインスタンスを取得する */ private function getInstanceAtDepth( depth:int ):DisplayObject { return _dict[ depth ]; } } }