blob: 95cb6e65521e1ae64a51b713d9fd521fc4a969d4 [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 flow-based layout. Components are laid
* out in order from left to right. When a component cannot be placed
* without horizontal clipping, a new row is started. This class
* supports horizontal and vertical gaps. These are used for spacing
* between components.
*/
public class FlowLayout implements LayoutManager, Serializable
{
/** Constant that specifies left alignment. */
public static final int LEFT = 0;
/** Constant that specifies center alignment. */
public static final int CENTER = 1;
/** Constant that specifies right alignment. */
public static final int RIGHT = 2;
/** Constant that specifies alignment to leading edge of container's
* orientation. */
public static final int LEADING = 3;
/** Constant that specifies alignment to trailing edge of container's
* orientation. */
public static final int TRAILING = 4;
/** Add a new component to the layout. This particular implementation
* does nothing.
*/
public void addLayoutComponent (String name, Component comp)
{
// Nothing.
}
/** Return the alignment. */
public int getAlignment ()
{
return align;
}
/** Return the horizontal gap. */
public int getHgap ()
{
return hgap;
}
/** Return the vertical gap. */
public int getVgap ()
{
return vgap;
}
/** Create a new FlowLayout with center alignment.
* Both gaps are set to 0.
*/
public FlowLayout ()
{
this (CENTER, 0, 0);
}
/** Create a new FlowLayout with the alignment.
* columns. Both gaps are set to 0.
* @param align Alignment
*/
public FlowLayout (int align)
{
this (align, 0, 0);
}
/** Create a new FlowLayout with the specified alignment and gaps.
* @param align Alignment
* @param hgap The horizontal gap
* @param vgap The vertical gap
* @exception IllegalArgumentException If either gap is negative
*/
public FlowLayout (int align, int hgap, int vgap)
{
if (hgap < 0)
throw new IllegalArgumentException ("horizontal gap must be nonnegative");
if (vgap < 0)
throw new IllegalArgumentException ("vertical gap must be nonnegative");
if (align != LEFT && align != RIGHT && align != CENTER
&& align != LEADING && align != TRAILING)
throw new IllegalArgumentException ("invalid align: " + align);
this.align = align;
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;
Dimension d = parent.getSize ();
Insets ins = parent.getInsets ();
ComponentOrientation orient = parent.getComponentOrientation ();
boolean left_to_right = orient.isLeftToRight ();
int y = ins.top + vgap;
int i = 0;
while (i < num)
{
// Find the components which go in the current row.
int new_w = ins.left + hgap + ins.right;
int new_h = 0;
int j;
for (j = i; j < num; ++j)
{
// FIXME: this is very inefficient.
Dimension c = comps[i].getPreferredSize ();
int next_w = new_w + hgap + c.width;
if (next_w > d.width)
{
// We must start a new row.
break;
}
new_w = next_w;
new_h = Math.max (new_h, c.height);
}
// We always need at least one item.
if (j == i)
++j;
// Set the location of each component for this row.
int x;
int myalign = align;
if (align == LEADING)
myalign = left_to_right ? LEFT : RIGHT;
else if (align == TRAILING)
myalign = left_to_right ? RIGHT : LEFT;
if (myalign == LEFT)
x = ins.left + hgap;
else if (myalign == CENTER)
x = (d.width - new_w) / 2;
else
x = d.width - new_w;
for (int k = i; i < j; ++k)
{
// FIXME: this is very inefficient.
Dimension c = comps[i].getPreferredSize ();
comps[i].setLocation (x, y);
x += c.width + vgap;
}
// Advance to next row.
i = j;
y += new_h + vgap;
}
}
/** 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 alignment.
* @param align The alignment
*/
public void setAlignment (int align)
{
if (align != LEFT && align != RIGHT && align != CENTER
&& align != LEADING && align != TRAILING)
throw new IllegalArgumentException ("invalid align: " + align);
this.align = align;
}
/** 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 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
+ ",align=" + align + "]");
}
// This method is used to compute the various sizes.
private Dimension getSize (Container parent, boolean is_min)
{
int w, h, num = parent.getComponentCount ();
// This is more efficient than calling getComponents().
Component[] comps = parent.component;
w = 0;
h = 0;
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 += d.width;
h = Math.max (d.height, h);
}
Insets ins = parent.getInsets ();
w += (num + 1) * hgap + ins.left + ins.right;
h += 2 * vgap + ins.top + ins.bottom;
return new Dimension (w, h);
}
// Alignment.
private int align;
// The gaps.
private int hgap;
private int vgap;
}