1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4  
     5  import org.aswing.*;
     6  import org.aswing.geom.*;
     7  
     8  /**
     9   * A border layout lays out a container, arranging and resizing
    10   * its components to fit in five regions:
    11   * north, south, east, west, and center.
    12   * Each region may contain no more than one component, and 
    13   * is identified by a corresponding constant:
    14   * <code>NORTH</code>, <code>SOUTH</code>, <code>EAST</code>,
    15   * <code>WEST</code>, and <code>CENTER</code>.  When adding a
    16   * component to a container with a border layout, use one of these
    17   * five constants, for example:
    18   * <pre>
    19   *    Panel p = new Panel();
    20   *    p.setLayout(new BorderLayout());
    21   *    p.add(new Button("Okay"), BorderLayout.SOUTH);
    22   * </pre>
    23   * As a convenience, <code>BorderLayout</code> interprets the
    24   * absence of a string specification the same as the constant
    25   * <code>CENTER</code>:
    26   * <pre>
    27   *    Panel p2 = new Panel();
    28   *    p2.setLayout(new BorderLayout());
    29   *    p2.add(new TextArea());  // Same as p.add(new TextArea(), BorderLayout.CENTER);
    30   * </pre>
    31   * 
    32   * @author iiley
    33   */
    34  class org.aswing.BorderLayout extends EmptyLayout{
    35  	private var hgap:Number;
    36  
    37  	private var vgap:Number;
    38  
    39  	private var north:Component;
    40  
    41  	private var west:Component;
    42  
    43  	private var east:Component;
    44  
    45      private var south:Component;
    46  
    47  	private var center:Component;
    48      
    49      private var firstLine:Component;
    50  
    51  	private var lastLine:Component;
    52  
    53  	private var firstItem:Component;
    54  
    55  	private var lastItem:Component;
    56  
    57      /**
    58       * The north layout constraint (top of container).
    59       */
    60      public static var NORTH:String  = "North";
    61  
    62      /**
    63       * The south layout constraint (bottom of container).
    64       */
    65      public static var SOUTH:String  = "South";
    66  
    67      /**
    68       * The east layout constraint (right side of container).
    69       */
    70      public static var EAST :String  = "East";
    71  
    72      /**
    73       * The west layout constraint (left side of container).
    74       */
    75      public static var WEST :String  = "West";
    76  
    77      /**
    78       * The center layout constraint (middle of container).
    79       */
    80      public static var CENTER:String  = "Center";
    81  
    82  
    83      public static var BEFORE_FIRST_LINE:String  = "First";
    84  
    85  
    86      public static var AFTER_LAST_LINE:String  = "Last";
    87  
    88  
    89      public static var BEFORE_LINE_BEGINS:String  = "Before";
    90  
    91  
    92      public static var AFTER_LINE_ENDS:String  = "After";
    93  
    94  
    95      public static var PAGE_START:String  = BEFORE_FIRST_LINE;
    96  
    97  
    98      public static var PAGE_END:String  = AFTER_LAST_LINE;
    99  
   100  
   101      public static var LINE_START:String  = BEFORE_LINE_BEGINS;
   102  
   103  
   104      public static var LINE_END:String  = AFTER_LINE_ENDS;
   105  
   106      /**
   107       * Constructs a border layout with the specified gaps
   108       * between components.
   109       * The horizontal gap is specified by <code>hgap</code>
   110       * and the vertical gap is specified by <code>vgap</code>.
   111       * @param   hgap   the horizontal gap.
   112       * @param   vgap   the vertical gap.
   113       */
   114      public function BorderLayout(hgap:Number, vgap:Number) {
   115      	if(hgap == undefined) hgap = 0;
   116      	if(vgap == undefined) vgap = 0;
   117  		this.hgap = hgap;
   118  		this.vgap = vgap;
   119      }
   120  
   121      public function getHgap():Number {
   122  		return hgap;
   123      }
   124  
   125      public function setHgap(hgap:Number):Void {
   126  		this.hgap = hgap;
   127      }
   128  
   129      public function getVgap():Number {
   130  		return vgap;
   131      }
   132  
   133      public function setVgap(vgap:Number):Void {
   134  		this.vgap = vgap;
   135      }
   136  
   137      public function addLayoutComponent(comp:Component, constraints:Object):Void {
   138  	    addLayoutComponentByAlign(constraints.toString(), comp);
   139      }
   140  
   141      private function addLayoutComponentByAlign(name:String, comp:Component):Void {
   142  		if (name == null) {
   143  	   		name = CENTER;
   144  		}
   145  
   146  		if (CENTER == name) {
   147  		    center = comp;
   148  		} else if (NORTH == name) {
   149  		    north = comp;
   150  		} else if (SOUTH == name) {
   151  		    south = comp;
   152  		} else if (EAST == name) {
   153  		    east = comp;
   154  		} else if (WEST == name) {
   155  		    west = comp;
   156  		} else if (BEFORE_FIRST_LINE == name) {
   157  		    firstLine = comp;
   158  		} else if (AFTER_LAST_LINE == name) {
   159  		    lastLine = comp;
   160  		} else if (BEFORE_LINE_BEGINS == name) {
   161  		    firstItem = comp;
   162  		} else if (AFTER_LINE_ENDS == name) {
   163  		    lastItem = comp;
   164  		} else {
   165  			//defaut center
   166  		    center = comp;
   167  		}
   168      }
   169  
   170      public function removeLayoutComponent(comp:Component):Void {
   171  		if (comp == center) {
   172  		    center = null;
   173  		} else if (comp == north) {
   174  		    north = null;
   175  		} else if (comp == south) {
   176  		    south = null;
   177  		} else if (comp == east) {
   178  		    east = null;
   179  		} else if (comp == west) {
   180  		    west = null;
   181  		}
   182  		if (comp == firstLine) {
   183  		    firstLine = null;
   184  		} else if (comp == lastLine) {
   185  		    lastLine = null;
   186  		} else if (comp == firstItem) {
   187  		    firstItem = null;
   188  		} else if (comp == lastItem) {
   189  		    lastItem = null;
   190  		}
   191      }
   192  
   193      public function minimumLayoutSize(target:Container):Dimension {
   194  		var dim:Dimension = new Dimension(0, 0);
   195  	    var ltr:Boolean = true;
   196  	    var c:Component = null;
   197  		
   198  		var d:Dimension;
   199  		if ((c=getChild(EAST,ltr)) != null) {
   200  		    d = c.getMinimumSize();
   201  		    dim.width += d.width + hgap;
   202  		    dim.height = Math.max(d.height, dim.height);
   203  		}
   204  		if ((c=getChild(WEST,ltr)) != null) {
   205  		    d = c.getMinimumSize();
   206  		    dim.width += d.width + hgap;
   207  		    dim.height = Math.max(d.height, dim.height);
   208  		}
   209  		if ((c=getChild(CENTER,ltr)) != null) {
   210  		    d = c.getMinimumSize();
   211  		    dim.width += d.width;
   212  		    dim.height = Math.max(d.height, dim.height);
   213  		}
   214  		if ((c=getChild(NORTH,ltr)) != null) {
   215  		    d = c.getMinimumSize();
   216  		    dim.width = Math.max(d.width, dim.width);
   217  		    dim.height += d.height + vgap;
   218  		}
   219  		if ((c=getChild(SOUTH,ltr)) != null) {
   220  		    d = c.getMinimumSize();
   221  		    dim.width = Math.max(d.width, dim.width);
   222  		    dim.height += d.height + vgap;
   223  		}
   224  	
   225  		var insets:Insets = target.getInsets();
   226  		dim.width += insets.left + insets.right;
   227  		dim.height += insets.top + insets.bottom;
   228  	
   229  		return dim;
   230      }
   231  
   232      public function preferredLayoutSize(target:Container):Dimension {		
   233      	var dim:Dimension = new Dimension(0, 0);
   234  	    var ltr:Boolean = true;
   235  	    var c:Component = null;
   236  		
   237  		var d:Dimension;
   238  		if ((c=getChild(EAST,ltr)) != null) {
   239  		    d = c.getPreferredSize();
   240  		    dim.width += d.width + hgap;
   241  		    dim.height = Math.max(d.height, dim.height);
   242  		}
   243  		if ((c=getChild(WEST,ltr)) != null) {
   244  		    d = c.getPreferredSize();
   245  		    dim.width += d.width + hgap;
   246  		    dim.height = Math.max(d.height, dim.height);
   247  		}
   248  		if ((c=getChild(CENTER,ltr)) != null) {
   249  		    d = c.getPreferredSize();
   250  		    dim.width += d.width;
   251  		    dim.height = Math.max(d.height, dim.height);
   252  		}
   253  		if ((c=getChild(NORTH,ltr)) != null) {
   254  		    d = c.getPreferredSize();
   255  		    dim.width = Math.max(d.width, dim.width);
   256  		    dim.height += d.height + vgap;
   257  		}
   258  		if ((c=getChild(SOUTH,ltr)) != null) {
   259  		    d = c.getPreferredSize();
   260  		    dim.width = Math.max(d.width, dim.width);
   261  		    dim.height += d.height + vgap;
   262  		}
   263  	
   264  		var insets:Insets = target.getInsets();
   265  		dim.width += insets.left + insets.right;
   266  		dim.height += insets.top + insets.bottom;
   267  		return dim;
   268      }
   269  
   270      public function getLayoutAlignmentX(target:Container):Number{
   271      	return 0.5;
   272      }
   273  
   274      public function getLayoutAlignmentY(target:Container):Number{
   275      	return 0.5;
   276      }
   277  
   278      /**
   279       * Lays out the container argument using this border layout.
   280       * <p>
   281       * This method actually reshapes the components in the specified
   282       * container in order to satisfy the constraints of this
   283       * <code>BorderLayout</code> object. The <code>NORTH</code>
   284       * and <code>SOUTH</code> components, if any, are placed at
   285       * the top and bottom of the container, respectively. The
   286       * <code>WEST</code> and <code>EAST</code> components are
   287       * then placed on the left and right, respectively. Finally,
   288       * the <code>CENTER</code> object is placed in any remaining
   289       * space in the middle.
   290       * <p>
   291       * Most applications do not call this method directly. This method
   292       * is called when a container calls its <code>doLayout</code> method.
   293       * @param   target   the container in which to do the layout.
   294       * @see     Container
   295       * @see     Container#doLayout()
   296       */
   297      public function layoutContainer(target:Container):Void{
   298      	var td:Dimension = target.getSize();
   299  		var insets:Insets = target.getInsets();
   300  		var top:Number = insets.top;
   301  		var bottom:Number = td.height - insets.bottom;
   302  		var left:Number = insets.left;
   303  		var right:Number = td.width - insets.right;
   304  	    var ltr:Boolean = true;
   305  	    var c:Component = null;
   306  	
   307  		var d:Dimension;
   308  		if ((c=getChild(NORTH,ltr)) != null) {
   309  		    d = c.getPreferredSize();
   310  		    c.setBounds(left, top, right - left, d.height);
   311  		    top += d.height + vgap;
   312  		}
   313  		if ((c=getChild(SOUTH,ltr)) != null) {
   314  		    d = c.getPreferredSize();
   315  		    c.setBounds(left, bottom - d.height, right - left, d.height);
   316  		    bottom -= d.height + vgap;
   317  		}
   318  		if ((c=getChild(EAST,ltr)) != null) {
   319  		    d = c.getPreferredSize();
   320  		    c.setBounds(right - d.width, top, d.width, bottom - top);
   321  		    right -= d.width + hgap;
   322  		    //Flashout.log("East prefer size : " + d);
   323  		}
   324  		if ((c=getChild(WEST,ltr)) != null) {
   325  		    d = c.getPreferredSize();
   326  		    c.setBounds(left, top, d.width, bottom - top);
   327  		    left += d.width + hgap;
   328  		}
   329  		if ((c=getChild(CENTER,ltr)) != null) {
   330  		    c.setBounds(left, top, right - left, bottom - top);
   331  		}
   332        
   333      }
   334  
   335      /**
   336       * Get the component that corresponds to the given constraint location
   337       *
   338       * @param   key     The desired absolute position,
   339       *                  either NORTH, SOUTH, EAST, or WEST.
   340       * @param   ltr     Is the component line direction left-to-right?
   341       */
   342      private function getChild(key:String, ltr:Boolean):Component {
   343          var result:Component = null;
   344  
   345          if (key == NORTH) {
   346              result = (firstLine != null) ? firstLine : north;
   347          }
   348          else if (key == SOUTH) {
   349              result = (lastLine != null) ? lastLine : south;
   350          }
   351          else if (key == WEST) {
   352              result = ltr ? firstItem : lastItem;
   353              if (result == null) {
   354                  result = west;
   355              }
   356          }
   357          else if (key == EAST) {
   358              result = ltr ? lastItem : firstItem;
   359              if (result == null) {
   360                  result = east;
   361              }
   362          }
   363          else if (key == CENTER) {
   364              result = center;
   365          }
   366          if (result != null && !result.isVisible()) {
   367              result = null;
   368          }
   369          return result;
   370      }
   371  
   372      public function toString():String {
   373  		return "BorderLayout[hgap=" + hgap + ",vgap=" + vgap + "]";
   374      }
   375  }
   376