blob: 976e3849035140cba30abe29cdb49b5634119312 [file] [log] [blame]
// GridLayout.java - Grid-based layout engine
/* Copyright (C) 2000 Free Software Foundation
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
package java.awt;
import java.io.Serializable;
/** This class implements a grid-based layout scheme. Components are
* all given the same size and are laid out from left to right and top
* to bottom. A GridLayout is configured with a number of rows and a
* number of columns. If either is zero then that dimension is
* computed based on the actual size of the container. An exception
* is thrown if an attempt is made to set both the number of rows and
* the number of columns to 0. This class also support horizontal and
* vertical gaps; these are used as spacing between cells.
*/
public class GridLayout implements LayoutManager, Serializable
{
/** Add a new component to the layout. This particular implementation
* does nothing.
*/
public void addLayoutComponent (String name, Component comp)
{
// Nothing.
}
/** Return the number of columns in this layout. */
public int getColumns ()
{
return cols;
}
/** Return the horizontal gap. */
public int getHgap ()
{
return hgap;
}
/** Return the number of rows in this layout. */
public int getRows ()
{
return rows;
}
/** Return the vertical gap. */
public int getVgap ()
{
return vgap;
}
/** Create a new GridLayout with one row and any number of columns.
* Both gaps are set to 0.
*/
public GridLayout ()
{
this (1, 0, 0, 0);
}
/** Create a new GridLayout with the specified number of rows and
* columns. Both gaps are set to 0.
* @param rows Number of rows
* @param cols Number of columns
* @exception IllegalArgumentException If rows and columns are both
* 0, or if either are negative
*/
public GridLayout (int rows, int cols)
{
this (rows, cols, 0, 0);
}
/** Create a new GridLayout with the specified number of rows and
* columns and the specified gaps.
* @param rows Number of rows
* @param cols Number of columns
* @param hgap The horizontal gap
* @param vgap The vertical gap
* @exception IllegalArgumentException If rows and columns are both
* 0, if either are negative, or if either gap is negative
*/
public GridLayout (int rows, int cols, int hgap, int vgap)
{
if (rows < 0)
throw new IllegalArgumentException ("number of rows cannot be negative");
if (cols < 0)
throw new IllegalArgumentException ("number of columns cannot be negative");
if (rows == 0 && cols == 0)
throw new IllegalArgumentException ("both rows and columns cannot be 0");
if (hgap < 0)
throw new IllegalArgumentException ("horizontal gap must be nonnegative");
if (vgap < 0)
throw new IllegalArgumentException ("vertical gap must be nonnegative");
this.rows = rows;
this.cols = cols;
this.hgap = hgap;
this.vgap = vgap;
}
/** Lay out the container's components based on current settings.
* @param parent The parent container
*/
public void layoutContainer (Container parent)
{
int num = parent.getComponentCount ();
// This is more efficient than calling getComponents().
Component[] comps = parent.component;
int real_rows = rows;
int real_cols = cols;
if (real_rows == 0)
real_rows = (num + real_cols - 1) / real_cols;
else
real_cols = (num + real_rows - 1) / real_rows;
Dimension d = parent.getSize ();
Insets ins = parent.getInsets ();
int tw = d.width - ins.left - ins.right;
int th = d.height - ins.top - ins.bottom;
int w = (tw - (real_rows - 1) * hgap) / real_rows;
int h = (th - (real_cols - 1) * vgap) / real_cols;
int x = ins.left;
int y = ins.top;
int i = 0;
int recount = 0;
while (i < num)
{
comps[i].setBounds (x, y, tw, th);
++i;
++recount;
if (recount == real_cols)
{
recount = 0;
y += vgap + th;
x = ins.left;
}
else
x += hgap + tw;
}
}
/** Get the minimum layout size of the container.
* @param cont The parent container
*/
public Dimension minimumLayoutSize (Container cont)
{
return getSize (cont, true);
}
/** Get the preferred layout size of the container.
* @param cont The parent container
*/
public Dimension preferredLayoutSize (Container cont)
{
return getSize (cont, false);
}
/** Remove the indicated component from this layout manager.
* This particular implementation does nothing.
* @param comp The component to remove
*/
public void removeLayoutComponent (Component comp)
{
// Nothing.
}
/** Set the number of columns.
* @param newCols
* @exception IllegalArgumentException If the number of columns is
* negative, or if the number of columns is zero and the number
* of rows is already 0.
*/
public void setColumns (int newCols)
{
if (cols < 0)
throw new IllegalArgumentException ("number of columns cannot be negative");
if (newCols == 0 && rows == 0)
throw new IllegalArgumentException ("number of rows is already 0");
this.cols = newCols;
}
/** Set the horizontal gap
* @param hgap The horizontal gap
*/
public void setHgap (int hgap)
{
if (hgap < 0)
throw new IllegalArgumentException ("horizontal gap must be nonnegative");
this.hgap = hgap;
}
/** Set the number of rows
* @param newRows
* @exception IllegalArgumentException If the number of rows is
* negative, or if the number of rows is zero and the number
* of columns is already 0.
*/
public void setRows (int newRows)
{
if (rows < 0)
throw new IllegalArgumentException ("number of rows cannot be negative");
if (newRows == 0 && cols == 0)
throw new IllegalArgumentException ("number of columns is already 0");
this.rows = newRows;
}
/** Set the vertical gap.
* @param vgap The vertical gap
*/
public void setVgap (int vgap)
{
if (vgap < 0)
throw new IllegalArgumentException ("vertical gap must be nonnegative");
this.vgap = vgap;
}
/** Return String description of this object. */
public String toString ()
{
return ("[" + getClass ().getName ()
+ ",hgap=" + hgap + ",vgap=" + vgap
+ ",rows=" + rows + ",cols=" + cols
+ "]");
}
// This method is used to compute the various sizes.
private Dimension getSize (Container parent, boolean is_min)
{
int w = 0, h = 0, num = parent.getComponentCount ();
// This is more efficient than calling getComponents().
Component[] comps = parent.component;
for (int i = 0; i < num; ++i)
{
// FIXME: can we just directly read the fields in Component?
// Or will that not work with subclassing?
Dimension d;
if (is_min)
d = comps[i].getMinimumSize ();
else
d = comps[i].getPreferredSize ();
w = Math.max (d.width, w);
h = Math.max (d.height, h);
}
int real_rows = rows;
int real_cols = cols;
if (real_rows == 0)
real_rows = (num + real_cols - 1) / real_cols;
else
real_cols = (num + real_rows - 1) / real_rows;
// We subtract out an extra gap here because the gaps are only
// between cells.
return new Dimension (real_rows * (w + hgap) - hgap,
real_cols * (h + vgap) - vgap);
}
// The gaps.
private int hgap;
private int vgap;
// Number of rows and columns.
private int rows;
private int cols;
}