1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4   
     5  import org.aswing.ASWingConstants;
     6  import org.aswing.Container;
     7  import org.aswing.geom.Dimension;
     8  import org.aswing.geom.Rectangle;
     9  import org.aswing.graphices.Graphics;
    10  import org.aswing.graphices.SolidBrush;
    11  import org.aswing.utils.MCUtils;
    12  
    13  /**
    14   * Abstract class for A container with a decorative floor movieclip.
    15   * <p> External content will be load automatically when the pane was create on the stage if floorEnabled.
    16   * @see org.aswing.JLoadPane
    17   * @see org.aswing.JAttachPane
    18   * @author iiley
    19   */
    20  class org.aswing.FloorPane extends Container {
    21  	
    22  	/**
    23  	 * preffered size of this component will be the fit to contain both size of extenal image/animation
    24  	 *  and counted from <code>LayoutManager</code>
    25  	 */
    26  	public static var PREFER_SIZE_BOTH:Number = 0;
    27  	/**
    28  	 * preffered size of this component will be the size of extenal image/animation
    29  	 */
    30  	public static var PREFER_SIZE_IMAGE:Number = 1;
    31  	/**
    32  	 * preffered size of this component will be counted by <code>LayoutManager</code>
    33  	 */	
    34  	public static var PREFER_SIZE_LAYOUT:Number = 2; 	
    35  	
    36  	/**
    37  	 * A fast access to ASWingConstants Constant
    38  	 * @see org.aswing.ASWingConstants
    39  	 */
    40  	public static var CENTER:Number  = ASWingConstants.CENTER;
    41  	/**
    42  	 * A fast access to ASWingConstants Constant
    43  	 * @see org.aswing.ASWingConstants
    44  	 */
    45  	public static var TOP:Number     = ASWingConstants.TOP;
    46  	/**
    47  	 * A fast access to ASWingConstants Constant
    48  	 * @see org.aswing.ASWingConstants
    49  	 */
    50      public static var LEFT:Number    = ASWingConstants.LEFT;
    51  	/**
    52  	 * A fast access to ASWingConstants Constant
    53  	 * @see org.aswing.ASWingConstants
    54  	 */
    55      public static var BOTTOM:Number  = ASWingConstants.BOTTOM;
    56   	/**
    57  	 * A fast access to ASWingConstants Constant
    58  	 * @see org.aswing.ASWingConstants
    59  	 */
    60      public static var RIGHT:Number   = ASWingConstants.RIGHT;
    61      
    62      private var path:String;
    63  	private var floorEnabled:Boolean;
    64  	private var floorMC:MovieClip;
    65  	private var floorMCDepth:Number;
    66  	private var floorMCMask:MovieClip;
    67  	private var floorMCMaskDepth:Number;
    68  	private var maskFloor:Boolean;
    69  	private var floorLoaded:Boolean;
    70  	private var prefferSizeStrategy:Number;
    71      private var verticalAlignment:Number;
    72      private var horizontalAlignment:Number;
    73      private var scaleImage:Boolean;
    74      private var floorOriginalSize:Dimension;
    75      private var hadscaled:Boolean;
    76      private var offsetX:Number;
    77      private var offsetY:Number;
    78  	
    79  	/**
    80  	 * FloorPane(path:String, prefferSizeStrategy:Number) <br>
    81  	 * FloorPane(path:String) prefferSizeStrategy default to PREFER_SIZE_BOTH<br>
    82  	 * FloorPane() path default to null,prefferSizeStrategy default to PREFER_SIZE_BOTH
    83  	 * <p>
    84  	 * Creates a FloorPane with a path to load external content.
    85  	 * @param path the path of the external content.
    86  	 * @param prefferSizeStrategy the prefferedSize count strategy. Must be one of below:
    87  	 * <ul>
    88  	 * <li>{@link #PREFER_SIZE_BOTH}
    89  	 * <li>{@link #PREFER_SIZE_IMAGE}
    90  	 * <li>{@link #PREFER_SIZE_LAYOUT}
    91  	 * </ul>
    92  	 * @see #setPath()
    93  	 */
    94  	private function FloorPane(path:String, prefferSizeStrategy:Number) {
    95  		super();
    96  		
    97  		this.path = path;
    98  		if(prefferSizeStrategy == undefined){
    99  			prefferSizeStrategy = PREFER_SIZE_BOTH;
   100  		}
   101  		this.prefferSizeStrategy = prefferSizeStrategy;
   102  		
   103      	verticalAlignment = TOP;
   104      	horizontalAlignment = LEFT;
   105      	scaleImage = false;
   106      	hadscaled = false;
   107      	maskFloor = true;
   108  		floorOriginalSize = null;
   109  		floorEnabled = true;
   110  		floorLoaded = false;
   111  		offsetX = 0;
   112  		offsetY = 0;
   113  	}
   114  
   115  	
   116  	/**
   117  	 * Sets the path to load/attach image/animation file or symbol.
   118  	 * This method will cause <code>reload()</code> action if the path 
   119  	 * is different from old one.
   120  	 * @param path the path of external image/animation file or the linkageID of a symbol.
   121  	 * @see #reload()
   122  	 */
   123  	public function setPath(path:String):Void{
   124  		if(path != this.path){
   125  			this.path = path;
   126  			reload();
   127  		}
   128  	}
   129  	
   130  	public function getPath():String{
   131  		return path;
   132  	}
   133  	
   134  	/**
   135  	 * Sets the preffered size counting strategy. Must be one of below:
   136  	 * <ul>
   137  	 * <li>{@link #PREFER_SIZE_BOTH}
   138  	 * <li>{@link #PREFER_SIZE_IMAGE}
   139  	 * <li>{@link #PREFER_SIZE_LAYOUT}
   140  	 * </ul>
   141  	 */
   142  	public function setPrefferSizeStrategy(p:Number):Void{
   143  		prefferSizeStrategy = p;
   144  	}
   145  	
   146  	/**
   147  	 * Returns the preffered size counting strategy.
   148  	 * @see #setPrefferSizeStrategy()
   149  	 */
   150  	public function getPrefferSizeStrategy():Number{
   151  		return prefferSizeStrategy;
   152  	}	
   153  	
   154      /**
   155       * Returns the vertical alignment of the image/animation.
   156       *
   157       * @return the <code>verticalAlignment</code> property, one of the
   158       *		following values: 
   159       * <ul>
   160       * <li>ASWingConstants.CENTER (the default)
   161       * <li>ASWingConstants.TOP
   162       * <li>ASWingConstants.BOTTOM
   163       * </ul>
   164       */
   165      public function getVerticalAlignment():Number {
   166          return verticalAlignment;
   167      }
   168      
   169      /**
   170       * Sets the vertical alignment of the image/animation. 
   171       * @param alignment  one of the following values:
   172       * <ul>
   173       * <li>ASWingConstants.CENTER (the default)
   174       * <li>ASWingConstants.TOP
   175       * <li>ASWingConstants.BOTTOM
   176       * </ul>
   177       * Default is TOP.
   178       */
   179      public function setVerticalAlignment(alignment:Number):Void {
   180          if (alignment == verticalAlignment){
   181          	return;
   182          }else{
   183          	verticalAlignment = alignment;
   184          	revalidate();
   185          }
   186      }
   187      
   188      /**
   189       * Returns the horizontal alignment of the image/animation.
   190       * @return the <code>horizontalAlignment</code> property,
   191       *		one of the following values:
   192       * <ul>
   193       * <li>ASWingConstants.RIGHT (the default)
   194       * <li>ASWingConstants.LEFT
   195       * <li>ASWingConstants.CENTER
   196       * </ul>
   197       * Default is LEFT.
   198       */
   199      public function getHorizontalAlignment():Number{
   200          return horizontalAlignment;
   201      }
   202      
   203      /**
   204       * Sets the horizontal alignment of the image/animation.
   205       * @param alignment  one of the following values:
   206       * <ul>
   207       * <li>ASWingConstants.RIGHT (the default)
   208       * <li>ASWingConstants.LEFT
   209       * <li>ASWingConstants.CENTER
   210       * </ul>
   211       */
   212      public function setHorizontalAlignment(alignment:Number):Void {
   213          if (alignment == horizontalAlignment){
   214          	return;
   215          }else{
   216          	horizontalAlignment = alignment;     
   217          	revalidate();
   218          }
   219      }
   220      
   221      /**
   222       * Sets whether need scale the loaded image/animation to fit the pane's size.
   223       * <p><b>Note:</b>Take care to use scaleImage to load a swf, because swf has different size at different frame or
   224       *  when some symbol invisible/visible.
   225       * @param b whether need scale the loaded image/animation to fit the pane's size.
   226       */
   227      public function setScaleImage(b:Boolean):Void{
   228      	if(scaleImage != b){
   229      		scaleImage = b;
   230      		revalidate();
   231      	}
   232      }
   233      
   234      /**
   235       * Returns whether need scale the loaded image/animation to fit the pane's size.
   236       * @return whether need scale the loaded image/animation to fit the pane's size.
   237       */
   238      public function isScaleImage():Boolean{
   239      	return scaleImage;
   240      }
   241      
   242      /**
   243       * Sets the x offset of the position of the loaded image/animation.
   244       * If you dont want to locate the content to the topleft of the pane, you can set the offsets.
   245       * @param offset the x offset 
   246       */
   247      public function setOffsetX(offset:Number):Void{
   248      	if(offsetX != offset){
   249      		offsetX = offset;
   250      		revalidate();
   251      	}
   252      }
   253      
   254      /**
   255       * Sets the y offset of the position of the loaded image/animation.
   256       * If you dont want to locate the content to the topleft of the pane, you can set the offsets.
   257       * @param offset the y offset 
   258       */
   259      public function setOffsetY(offset:Number):Void{
   260      	if(offsetY != offset){
   261      		offsetY = offset;
   262      		revalidate();
   263      	}
   264      }    
   265      
   266      /**
   267       * @see #setOffsetX()
   268       */
   269      public function getOffsetX():Number{
   270      	return offsetX;
   271      }
   272      
   273      /**
   274       * @see #setOffsetY()
   275       */
   276      public function getOffsetY():Number{
   277      	return offsetY;
   278      }
   279  		
   280  	/**
   281  	 * Returns the floor target movie clip.<br>
   282  	 * You should take care to do operation at this MC, if you remove it, 
   283  	 * the component will create another instead when next reload.
   284  	 * @return the movieclip where the extenal image/animation will be loaded in or 
   285  	 * the movieclip attached.
   286  	 * @see #getFloorMC()
   287  	 * @see org.aswing.JLoadPane
   288  	 * @see org.aswing.JAttachPane
   289  	 */
   290  	public function getFloorMC():MovieClip{
   291  		return floorMC;
   292  	}
   293  	
   294  	/**
   295  	 * Disable the load ability.
   296  	 * Removes loaded image or animation(by remove the LoadTarget MovieClip). And will not load any thing from now on.
   297  	 * @see #getFloorMC()
   298  	 * @see #enableFloor()
   299  	 * @see #isEnabledFloor()
   300  	 * @see #reload()
   301  	 */
   302  	public function disableFloor():Void{
   303  		if(floorEnabled){
   304  			floorEnabled = false;
   305  			setLoaded(false);
   306  			removeFloorMCs();
   307  		}
   308  	}
   309  	
   310  	/**
   311  	 * Enable the load ability, can call reload to try to load content if it is not loaded yet.
   312  	 * @see #isEnabledFloor()
   313  	 * @see #enableFloor()
   314  	 * @see #reload()
   315  	 */
   316  	public function enableFloor():Void{
   317  		if(!floorEnabled){
   318  			floorEnabled = true;
   319  			reload();
   320  		}
   321  	}
   322  	
   323  	/**
   324  	 * Returns whether load function is enabled. Default is true.
   325  	 * @see #enableFloor()
   326  	 * @see #disableFloor()
   327  	 */
   328  	public function isEnabledFloor():Boolean{
   329  		return floorEnabled;
   330  	}
   331  	
   332  	/**
   333  	 * Returns is the extenal image/animation file was loaded ok.
   334  	 * @return true if the file loaded ok, otherwish return false
   335  	 */
   336  	public function isLoaded():Boolean{
   337  		return floorLoaded;
   338  	}
   339  	
   340  	/**
   341  	 * Returns the extenal image/animation/symbol 's original size.
   342  	 * If the external content are not loaded yet, return null.
   343  	 * @return the extenal content's original size. null if it is not loaded yet.
   344  	 */
   345  	public function getFloorOriginalSize():Dimension{
   346  		if(isLoaded()){
   347  			return floorOriginalSize;
   348  		}else{
   349  			return null;
   350  		}
   351  	}
   352  	
   353  
   354  	
   355  	private function create():Void{
   356  		super.create();
   357  		if(MCUtils.isMovieClipExist(target_mc)){
   358  			floorMCDepth = target_mc.getNextHighestDepth();
   359  			floorMCMaskDepth = floorMCDepth + 1;
   360  			reload();
   361  		}
   362  	}
   363  	
   364  	/**
   365  	 * layout this container
   366  	 */
   367  	public function doLayout():Void{
   368  		super.doLayout();
   369  		fitImage();
   370  	}	
   371  	
   372  	private function fitImage():Void{
   373  		if(isLoaded()){
   374  			var b:Rectangle = getPaintBounds();
   375  			floorMCMask._x = b.x;
   376  			floorMCMask._y = b.y;
   377  			floorMCMask._width = b.width;
   378  			floorMCMask._height = b.height;
   379  			if(scaleImage){
   380  				floorMC._x = b.x - offsetX;
   381  				floorMC._y = b.y - offsetY;
   382  				floorMC._width = b.width - offsetX;
   383  				floorMC._height = b.height - offsetY;
   384  				hadscaled = true;
   385  			}else{
   386  				if(hadscaled){
   387  					if(floorMC._width != floorOriginalSize.width){
   388  						floorMC._width = floorOriginalSize.width;
   389  					}
   390  					if(floorMC._height != floorOriginalSize.height){
   391  						floorMC._height = floorOriginalSize.height;
   392  					}
   393  					hadscaled = false;
   394  				}
   395  				var mx:Number, my:Number;
   396  				if(horizontalAlignment == CENTER){
   397  					mx = b.x + (b.width - floorOriginalSize.width)/2;
   398  				}else if(horizontalAlignment == RIGHT){
   399  					mx = b.x + (b.width - floorOriginalSize.width);
   400  				}else{
   401  					mx = b.x;
   402  				}
   403  				if(verticalAlignment == CENTER){
   404  					my = b.y + (b.height - floorOriginalSize.height)/2;
   405  				}else if(verticalAlignment == BOTTOM){
   406  					my = b.y + (b.height - floorOriginalSize.height);
   407  				}else{
   408  					my = b.y;
   409  				}
   410  				floorMC._x = mx - offsetX;
   411  				floorMC._y = my - offsetY;
   412  			}
   413  		}
   414  	}
   415  	
   416  	
   417  	/**
   418  	 * count preffered size base on prefferSizeStrategy.
   419  	 */
   420  	private function countPreferredSize():Dimension{
   421  		var size:Dimension = null;
   422  		var sizeByMC:Dimension;
   423  		if(isLoaded()){
   424  			sizeByMC = new Dimension(floorOriginalSize.width - offsetX, floorOriginalSize.height - offsetY);
   425  			sizeByMC = getInsets().roundsSize(sizeByMC);
   426  		}else{
   427  			sizeByMC = super.countPreferredSize();
   428  		}
   429  		
   430  		size = super.countPreferredSize();
   431  				
   432  		if(prefferSizeStrategy == PREFER_SIZE_IMAGE){
   433  			return sizeByMC;
   434  		}else if(prefferSizeStrategy == PREFER_SIZE_LAYOUT){
   435  			return size;
   436  		}else{
   437  			return new Dimension(
   438  				Math.max(sizeByMC.width, size.width), 
   439  				Math.max(sizeByMC.height, size.height));
   440  		}
   441  	}	
   442  	
   443  	/**
   444  	 * Reload the floor image/animation when enabledFoor. otherwish do nothing.
   445  	 * @see #loadFloor()
   446  	 * @see #createFloorMC()
   447  	 * @see #createFloorMaskMC()
   448  	 * @see org.aswing.JLoadPane
   449  	 * @see org.aswing.JAttachPane
   450  	 */
   451  	public function reload():Void{
   452  		if(isEnabledFloor()){
   453  			removeFloorMCs();
   454  			floorMC = createFloorMC();
   455  			floorMCMask = createFloorMaskMC(floorMC);
   456  			setMaskFloor(maskFloor);
   457  			setLoaded(false);
   458  			loadFloor();
   459  		}
   460  	}
   461  	
   462  	public function isMaskFloor():Boolean{
   463  		return maskFloor;
   464  	}
   465  	
   466  	public function setMaskFloor(m:Boolean):Void{
   467  		maskFloor = m;
   468  		if(m){
   469  			floorMC.setMask(floorMCMask);
   470  			floorMCMask._visible = true;
   471  		}else{
   472  			floorMCMask._visible = false;
   473  			floorMC.setMask(null);
   474  		}
   475  	}
   476  	
   477  	private function removeFloorMCs():Void{
   478  		floorMC.setMask(null);
   479  		floorMC.unloadMovie();
   480  		floorMC.removeMovieClip();
   481  		floorMCMask.clear(); //just clear it, not remove, intend to hold the depths
   482  		floorMC = floorMCMask = null;
   483  	}
   484  	
   485  	/**
   486  	 * Creates mask movieclip at the depth above floorMC.
   487  	 */
   488  	private function createFloorMaskMC(floorMC:MovieClip):MovieClip{
   489  		if(MCUtils.isMovieClipExist(floorMC)){
   490  			var parentMC:MovieClip = MovieClip(floorMC._parent);
   491  			floorMCMask = creater.createMC(parentMC, "floorMask", getFloorMaskDepth());
   492  			var g:Graphics = new Graphics(floorMCMask);
   493  			g.fillRectangle(new SolidBrush(0), 0, 0, 1, 1);
   494  			return floorMCMask;
   495  		}else{
   496  			return null;
   497  		}
   498  	}
   499  	
   500  	private function setLoaded(b:Boolean):Void{
   501  		floorLoaded = b;
   502  	}
   503  	
   504  	private function setFloorOriginalSize(size:Dimension):Void{
   505  		floorOriginalSize = new Dimension(size.width, size.height);
   506  	}
   507  	
   508  	/**
   509  	 * Return the depth to create floor mc.
   510  	 */
   511  	private function getFloorDepth():Number{
   512  		return floorMCDepth;
   513  	}
   514  	
   515  	/**
   516  	 * Return the depth to create floor mask mc.
   517  	 */
   518  	private function getFloorMaskDepth():Number{
   519  		return floorMCMaskDepth;
   520  	}
   521  	//////////////////////
   522  	
   523  	/**
   524  	 * load the floor content.
   525  	 * <p> here it is empty.
   526  	 * Subclass must override this method to make loading.
   527  	 */
   528  	private function loadFloor():Void{
   529  	}
   530  	
   531  	/**
   532  	 * Create the floor mc.
   533  	 * <p> here it is empty.
   534  	 * Subclass must override this method to make creating.
   535  	 */
   536  	private function createFloorMC():MovieClip{
   537  		return null;
   538  	}
   539  }
   540