| // 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; |
| } |