1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4  
     5  /**
     6   * DepthManager to manage the depth of mcs created by AS.
     7   * 
     8   * <p>This Manager can not manage the mcs created by FlashIDE.
     9   * 
    10   * @author iiley
    11   */
    12  class org.aswing.utils.DepthManager{
    13  	public static var MAX_DEPTH:Number = 1048575;
    14  	public static var MIN_DEPTH:Number = 0;
    15  	
    16  	/**
    17  	 * bringToBottom(mc:MovieClip, exceptMC:MovieClip)<br>
    18  	 * bringToBottom(mc:MovieClip)
    19  	 * <p>
    20  	 * Bring the mc to all brother mcs' bottom.
    21  	 * <p>
    22  	 * if exceptMC is undefined or null, the mc will be sent to bottom of all.
    23  	 * else, the mc will be sent to the bottom of all but above the exceptMC.
    24  	 * If you use a exceptMC, make sure the exceptMC is always at the bottom of all mcs, unless, this 
    25  	 * method maybe weird(may throw Errors).
    26  	 * @param mc the mc to be set to bottom
    27  	 * @param exceptMC the exceptMC of bottom mc.
    28  	 * @see #isBottom()
    29  	 * @throws Error when the exceptMC is not at the bottom currently.
    30  	 */
    31  	public static function bringToBottom(mc:MovieClip, exceptMC:MovieClip):Void{
    32  		var parent:MovieClip = mc._parent;
    33  		if(parent == null) return;
    34  		if(mc.getDepth() == MIN_DEPTH) return;
    35  		
    36  		var minDepth:Number = (exceptMC == undefined ? MIN_DEPTH : exceptMC.getDepth()+1);
    37  		
    38  		if(parent.getInstanceAtDepth(minDepth) == undefined){
    39  			mc.swapDepths(minDepth);
    40  			return;
    41  		}
    42  		
    43  		var mcs:Array = createMCSequenced(parent);
    44  		if(mc == mcs[0]) return;
    45  		if(mc == mcs[1] && exceptMC == mcs[0]) return;
    46  		
    47  		if(exceptMC != mcs[0]){
    48  			trace("The exceptMC is not at the bottom currently!");
    49  			throw new Error("The exceptMC is not at the bottom currently!");
    50  		}
    51  		
    52  		var swapMC:MovieClip = mc;
    53  		for(var i:Number=1; mcs[i]!=mc; i++){
    54  			swapMC.swapDepths(mcs[i]);
    55  			swapMC = mcs[i];
    56  		}
    57  	}
    58  	
    59  	/**
    60  	 * Bring the mc to all brother mcs' top.
    61  	 */	
    62  	public static function bringToTop(mc:MovieClip):Void{
    63  		var parent:MovieClip = mc._parent;
    64  		if(parent == null) return;
    65  		var depth:Number = parent.getNextHighestDepth();
    66  		if(mc.getDepth() == (depth - 1)) return;
    67  		if(depth < MAX_DEPTH){
    68  			mc.swapDepths(depth);
    69  			return;
    70  		}
    71  		
    72  		var mcs:Array = createMCSequenced(parent);
    73  		if(mc == mcs[0]) return;
    74  		
    75  		var swapMC:MovieClip = mc;
    76  		for(var i:Number=mcs.length-1; mcs[i]!=mc; i--){
    77  			swapMC.swapDepths(mcs[i]);
    78  			swapMC = mcs[i];
    79  		}		
    80  	}
    81  	
    82  	/**
    83  	 * Returns is the mc is on the top depths in DepthManager's valid depths.
    84  	 * Valid depths is that depths from MIN_DEPTH to MAX_DEPTH.
    85  	 */
    86  	public static function isTop(mc:MovieClip):Boolean{
    87  		var parent:MovieClip = mc._parent;
    88  		if(parent == null) return true;
    89  		var depth:Number = parent.getNextHighestDepth();
    90  		return mc.getDepth() == (depth - 1);
    91  	}
    92  	
    93  	/**
    94  	 * isBottom(mc:MovieClip, exceptMC:MovieClip)<br>
    95  	 * isBottom(mc:MovieClip)
    96  	 * <p>
    97  	 * Returns is the mc is at the bottom depths in DepthManager's valid depths.
    98  	 * Valid depths is that depths from MIN_DEPTH to MAX_DEPTH.
    99  	 * <p>
   100  	 * if exceptMC is undefined or null, judge is the mc is at bottom of all.
   101  	 * else, the mc judge is the mc is at bottom of all except the exceptMC.
   102  	 * @param mc the mc to be set to bottom
   103  	 * @param exceptMC the exceptMC of bottom mc.
   104  	 * @return is the mc is at the bottom
   105  	 */
   106  	public static function isBottom(mc:MovieClip, exceptMC:MovieClip):Boolean{
   107  		var parent:MovieClip = mc._parent;
   108  		if(parent == null) return true;
   109  		var depth:Number = mc.getDepth();
   110  		if(depth == MIN_DEPTH){
   111  			return true;
   112  		}
   113  		for(var i:Number=MIN_DEPTH; i<depth; i++){
   114  			var mcAtDepth:MovieClip = parent.getInstanceAtDepth(i);
   115  			if(mcAtDepth != undefined && mcAtDepth != exceptMC){
   116  				return false;
   117  			}
   118  		}
   119  		return true;
   120  	}
   121  	
   122  	/**
   123  	 * Return if mc is just first bebow the aboveMC.
   124  	 * if them don't have the same parent, whatever depth they has just return false.
   125  	 */
   126  	public static function isJustBelow(mc:MovieClip, aboveMC:MovieClip):Boolean{
   127  		var parent:MovieClip = mc._parent;
   128  		if(parent == null) return false;
   129  		if(aboveMC._parent != parent) return false;
   130  		
   131  		if(mc.getDepth() >= aboveMC.getDepth()){
   132  			return false;
   133  		}else{
   134  			for(var i:Number=aboveMC.getDepth() - 1; i>=MIN_DEPTH; i--){
   135  				var t:MovieClip = parent.getInstanceAtDepth(i);
   136  				if(t != null){
   137  					if(t == mc){
   138  						return true;
   139  					}else{
   140  						return false;
   141  					}
   142  				}
   143  			}
   144  		}
   145  		return false;
   146  	}
   147  	
   148  	/**
   149  	 * Return if mc is just first above the belowMC.
   150  	 * if them don't have the same parent, whatever depth they has just return false.
   151  	 * @see #isJustBelow
   152  	 */	
   153  	public static function isJustAbove(mc:MovieClip, belowMC:MovieClip):Boolean{
   154  		return isJustBelow(belowMC, mc);
   155  	}
   156  		
   157  	/**
   158  	 * Create a sequence contains all mcs sorted by their depth.
   159  	 */
   160  	public static function createMCSequenced(parent:MovieClip):Array{
   161  		var mcs:Array = new Array();
   162  		for(var i:String in parent){
   163  			if(parent[i] instanceof MovieClip){
   164  				mcs.push(parent[i]);
   165  			}
   166  		}
   167  		mcs.sort(depthComparator);
   168  		return mcs;
   169  	}
   170  	
   171  	private static function depthComparator(a, b):Number{
   172  		if(a.getDepth() > b.getDepth()){
   173  			return -1;
   174  		}else{
   175  			return 1;
   176  		}
   177  	}
   178  }
   179