FlowLayout.java 6.73 KB
Newer Older
Tom Tromey committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// 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;

30 31 32 33 34 35 36
  /** 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;

Tom Tromey committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  /** 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");
92 93
    if (align != LEFT && align != RIGHT && align != CENTER
	&& align != LEADING && align != TRAILING)
Tom Tromey committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
      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 ();

112 113 114
    ComponentOrientation orient = parent.getComponentOrientation ();
    boolean left_to_right = orient.isLeftToRight ();

Tom Tromey committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    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;
142 143 144 145 146 147 148 149

	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)
Tom Tromey committed
150
	  x = ins.left + hgap;
151
	else if (myalign == CENTER)
Tom Tromey committed
152 153 154
	  x = (d.width - new_w) / 2;
	else
	  x = d.width - new_w;
155

Tom Tromey committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	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)
  {
200 201
    if (align != LEFT && align != RIGHT && align != CENTER
	&& align != LEADING && align != TRAILING)
Tom Tromey committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
      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;
}