2000-12-03 16:28:35 +08:00
|
|
|
// 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;
|
|
|
|
|
2000-12-26 08:25:13 +08:00
|
|
|
/** 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;
|
|
|
|
|
2000-12-03 16:28:35 +08:00
|
|
|
/** 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");
|
2000-12-26 08:25:13 +08:00
|
|
|
if (align != LEFT && align != RIGHT && align != CENTER
|
|
|
|
&& align != LEADING && align != TRAILING)
|
2000-12-03 16:28:35 +08:00
|
|
|
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 ();
|
|
|
|
|
2000-12-26 08:25:13 +08:00
|
|
|
ComponentOrientation orient = parent.getComponentOrientation ();
|
|
|
|
boolean left_to_right = orient.isLeftToRight ();
|
|
|
|
|
2000-12-03 16:28:35 +08:00
|
|
|
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;
|
2000-12-26 08:25:13 +08:00
|
|
|
|
|
|
|
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)
|
2000-12-03 16:28:35 +08:00
|
|
|
x = ins.left + hgap;
|
2000-12-26 08:25:13 +08:00
|
|
|
else if (myalign == CENTER)
|
2000-12-03 16:28:35 +08:00
|
|
|
x = (d.width - new_w) / 2;
|
|
|
|
else
|
|
|
|
x = d.width - new_w;
|
2000-12-26 08:25:13 +08:00
|
|
|
|
2000-12-03 16:28:35 +08:00
|
|
|
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)
|
|
|
|
{
|
2000-12-26 08:25:13 +08:00
|
|
|
if (align != LEFT && align != RIGHT && align != CENTER
|
|
|
|
&& align != LEADING && align != TRAILING)
|
2000-12-03 16:28:35 +08:00
|
|
|
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;
|
|
|
|
}
|