1. /*
  2. * @(#)GridBagLayout.java 1.37 00/02/02
  3. *
  4. * Copyright 1995-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.awt;
  11. import java.util.Hashtable;
  12. import java.util.Vector;
  13. class GridBagLayoutInfo implements java.io.Serializable {
  14. int width, height; /* number of cells horizontally, vertically */
  15. int startx, starty; /* starting point for layout */
  16. int minWidth[]; /* largest minWidth in each column */
  17. int minHeight[]; /* largest minHeight in each row */
  18. double weightX[]; /* largest weight in each column */
  19. double weightY[]; /* largest weight in each row */
  20. GridBagLayoutInfo () {
  21. minWidth = new int[GridBagLayout.MAXGRIDSIZE];
  22. minHeight = new int[GridBagLayout.MAXGRIDSIZE];
  23. weightX = new double[GridBagLayout.MAXGRIDSIZE];
  24. weightY = new double[GridBagLayout.MAXGRIDSIZE];
  25. }
  26. }
  27. /**
  28. * The <code>GridBagLayout</code> class is a flexible layout
  29. * manager that aligns components vertically and horizontally,
  30. * without requiring that the components be of the same size.
  31. * Each <code>GridBagLayout</code> object maintains a dynamic
  32. * rectangular grid of cells, with each component occupying
  33. * one or more cells, called its <em>display area</em>.
  34. * <p>
  35. * Each component managed by a grid bag layout is associated
  36. * with an instance of
  37. * {@link GridBagConstraints}
  38. * that specifies how the component is laid out within its display area.
  39. * <p>
  40. * How a <code>GridBagLayout</code> object places a set of components
  41. * depends on the <code>GridBagConstraints</code> object associated
  42. * with each component, and on the minimum size
  43. * and the preferred size of the components' containers.
  44. * <p>
  45. * To use a grid bag layout effectively, you must customize one or more
  46. * of the <code>GridBagConstraints</code> objects that are associated
  47. * with its components. You customize a <code>GridBagConstraints</code>
  48. * object by setting one or more of its instance variables:
  49. * <p>
  50. * <dl>
  51. * <dt>{@link GridBagConstraints#gridx},
  52. * {@link GridBagConstraints#gridy}
  53. * <dd>Specifies the cell at the upper left of the component's display area,
  54. * where the upper-left-most cell has address
  55. * <code>gridx = 0</code>,
  56. * <code>gridy = 0</code>.
  57. * Use <code>GridBagConstraints.RELATIVE</code> (the default value)
  58. * to specify that the component be just placed
  59. * just to the right of (for <code>gridx</code>)
  60. * or just below (for <code>gridy</code>)
  61. * the component that was added to the container
  62. * just before this component was added.
  63. * <dt>{@link GridBagConstraints#gridwidth},
  64. * {@link GridBagConstraints#gridheight}
  65. * <dd>Specifies the number of cells in a row (for <code>gridwidth</code>)
  66. * or column (for <code>gridheight</code>)
  67. * in the component's display area.
  68. * The default value is 1.
  69. * Use <code>GridBagConstraints.REMAINDER</code> to specify
  70. * that the component be the last one in its row (for <code>gridwidth</code>)
  71. * or column (for <code>gridheight</code>).
  72. * Use <code>GridBagConstraints.RELATIVE</code> to specify
  73. * that the component be the next to last one
  74. * in its row (for <code>gridwidth</code>)
  75. * or column (for <code>gridheight</code>).
  76. * <dt>{@link GridBagConstraints#fill}
  77. * <dd>Used when the component's display area
  78. * is larger than the component's requested size
  79. * to determine whether (and how) to resize the component.
  80. * Possible values are
  81. * <code>GridBagConstraints.NONE</code> (the default),
  82. * <code>GridBagConstraints.HORIZONTAL</code>
  83. * (make the component wide enough to fill its display area
  84. * horizontally, but don't change its height),
  85. * <code>GridBagConstraints.VERTICAL</code>
  86. * (make the component tall enough to fill its display area
  87. * vertically, but don't change its width), and
  88. * <code>GridBagConstraints.BOTH</code>
  89. * (make the component fill its display area entirely).
  90. * <dt>{@link GridBagConstraints#ipadx},
  91. * {@link GridBagConstraints#ipady}
  92. * <dd>Specifies the component's internal padding within the layout,
  93. * how much to add to the minimum size of the component.
  94. * The width of the component will be at least its minimum width
  95. * plus <code>(ipadx * 2)</code> pixels (since the padding
  96. * applies to both sides of the component). Similarly, the height of
  97. * the component will be at least the minimum height plus
  98. * <code>(ipady * 2)</code> pixels.
  99. * <dt>{@link GridBagConstraints#insets}
  100. * <dd>Specifies the component's external padding, the minimum
  101. * amount of space between the component and the edges of its display area.
  102. * <dt>{@link GridBagConstraints#anchor}
  103. * <dd>Used when the component is smaller than its display area
  104. * to determine where (within the display area) to place the component.
  105. * Valid values are
  106. * <code>GridBagConstraints.CENTER</code> (the default),
  107. * <code>GridBagConstraints.NORTH</code>,
  108. * <code>GridBagConstraints.NORTHEAST</code>,
  109. * <code>GridBagConstraints.EAST</code>,
  110. * <code>GridBagConstraints.SOUTHEAST</code>,
  111. * <code>GridBagConstraints.SOUTH</code>,
  112. * <code>GridBagConstraints.SOUTHWEST</code>,
  113. * <code>GridBagConstraints.WEST</code>, and
  114. * <code>GridBagConstraints.NORTHWEST</code>.
  115. * <dt>{@link GridBagConstraints#weightx},
  116. * {@link GridBagConstraints#weighty}
  117. * <dd>Used to determine how to distribute space, which is
  118. * important for specifying resizing behavior.
  119. * Unless you specify a weight for at least one component
  120. * in a row (<code>weightx</code>) and column (<code>weighty</code>),
  121. * all the components clump together in the center of their container.
  122. * This is because when the weight is zero (the default),
  123. * the <code>GridBagLayout</code> object puts any extra space
  124. * between its grid of cells and the edges of the container.
  125. * </dl>
  126. * <p>
  127. * The following figure shows ten components (all buttons)
  128. * managed by a grid bag layout:
  129. * <p>
  130. * <img src="doc-files/GridBagLayout-1.gif"
  131. * ALIGN=center HSPACE=10 VSPACE=7>
  132. * <p>
  133. * Each of the ten components has the <code>fill</code> field
  134. * of its associated <code>GridBagConstraints</code> object
  135. * set to <code>GridBagConstraints.BOTH</code>.
  136. * In addition, the components have the following non-default constraints:
  137. * <p>
  138. * <ul>
  139. * <li>Button1, Button2, Button3: <code>weightx = 1.0</code>
  140. * <li>Button4: <code>weightx = 1.0</code>,
  141. * <code>gridwidth = GridBagConstraints.REMAINDER</code>
  142. * <li>Button5: <code>gridwidth = GridBagConstraints.REMAINDER</code>
  143. * <li>Button6: <code>gridwidth = GridBagConstraints.RELATIVE</code>
  144. * <li>Button7: <code>gridwidth = GridBagConstraints.REMAINDER</code>
  145. * <li>Button8: <code>gridheight = 2</code>,
  146. * <code>weighty = 1.0</code>
  147. * <li>Button9, Button 10:
  148. * <code>gridwidth = GridBagConstraints.REMAINDER</code>
  149. * </ul>
  150. * <p>
  151. * Here is the code that implements the example shown above:
  152. * <p>
  153. * <hr><blockquote><pre>
  154. * import java.awt.*;
  155. * import java.util.*;
  156. * import java.applet.Applet;
  157. *
  158. * public class GridBagEx1 extends Applet {
  159. *
  160. * protected void makebutton(String name,
  161. * GridBagLayout gridbag,
  162. * GridBagConstraints c) {
  163. * Button button = new Button(name);
  164. * gridbag.setConstraints(button, c);
  165. * add(button);
  166. * }
  167. *
  168. * public void init() {
  169. * GridBagLayout gridbag = new GridBagLayout();
  170. * GridBagConstraints c = new GridBagConstraints();
  171. *
  172. * setFont(new Font("Helvetica", Font.PLAIN, 14));
  173. * setLayout(gridbag);
  174. *
  175. * c.fill = GridBagConstraints.BOTH;
  176. * c.weightx = 1.0;
  177. * makebutton("Button1", gridbag, c);
  178. * makebutton("Button2", gridbag, c);
  179. * makebutton("Button3", gridbag, c);
  180. *
  181. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  182. * makebutton("Button4", gridbag, c);
  183. *
  184. * c.weightx = 0.0; //reset to the default
  185. * makebutton("Button5", gridbag, c); //another row
  186. *
  187. * c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
  188. * makebutton("Button6", gridbag, c);
  189. *
  190. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  191. * makebutton("Button7", gridbag, c);
  192. *
  193. * c.gridwidth = 1; //reset to the default
  194. * c.gridheight = 2;
  195. * c.weighty = 1.0;
  196. * makebutton("Button8", gridbag, c);
  197. *
  198. * c.weighty = 0.0; //reset to the default
  199. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  200. * c.gridheight = 1; //reset to the default
  201. * makebutton("Button9", gridbag, c);
  202. * makebutton("Button10", gridbag, c);
  203. *
  204. * setSize(300, 100);
  205. * }
  206. *
  207. * public static void main(String args[]) {
  208. * Frame f = new Frame("GridBag Layout Example");
  209. * GridBagEx1 ex1 = new GridBagEx1();
  210. *
  211. * ex1.init();
  212. *
  213. * f.add("Center", ex1);
  214. * f.pack();
  215. * f.setSize(f.getPreferredSize());
  216. * f.show();
  217. * }
  218. * }
  219. * </pre></blockquote><hr>
  220. * <p>
  221. * @version 1.5, 16 Nov 1995
  222. * @author Doug Stein
  223. * @see java.awt.GridBagConstraints
  224. * @since JDK1.0
  225. */
  226. public class GridBagLayout implements LayoutManager2,
  227. java.io.Serializable {
  228. /**
  229. * The maximum number of grid positions (both horizontally and
  230. * vertically) that can be laid out by the grid bag layout.
  231. */
  232. protected static final int MAXGRIDSIZE = 512;
  233. /**
  234. * The smallest grid that can be laid out by the grid bag layout.
  235. */
  236. protected static final int MINSIZE = 1;
  237. protected static final int PREFERREDSIZE = 2;
  238. /**
  239. * This hashtable maintains the association between
  240. * a component and its gridbag constraints.
  241. * The Keys in comptable are the components and the
  242. * values are the instances of GridBagConstraints.
  243. *
  244. * @serial
  245. * @see java.awt.GridBagConstraints
  246. */
  247. protected Hashtable comptable;
  248. /**
  249. * This field holds a gridbag constraints instance
  250. * containing the default values, so if a component
  251. * does not have gridbag constraints associated with
  252. * it, then the component will be assigned a
  253. * copy of the <code>defaultConstraints</code>.
  254. *
  255. * @serial
  256. * @see #getConstraints(Component)
  257. * @see #setConstraints(Component, GridBagConstraints)
  258. * @see #lookupConstraints(Component)
  259. */
  260. protected GridBagConstraints defaultConstraints;
  261. /**
  262. * This field holds tha layout information
  263. * for the gridbag. The information in this field
  264. * is based on the most recent validation of the
  265. * gridbag.
  266. * If <code>layoutInfo</code> is <code>null</code>
  267. * this indicates that there are no components in
  268. * the gridbag or if there are components, they have
  269. * not yet been validated.
  270. *
  271. * @serial
  272. * @see #GetLayoutInfo(Container, int)
  273. */
  274. protected GridBagLayoutInfo layoutInfo;
  275. /**
  276. * This field holds the overrides to the column minimum
  277. * width. If this field is non-null the values are
  278. * applied to the gridbag after all of the minimum columns
  279. * widths have been calculated.
  280. * If columnWidths has more elements than the number of
  281. * columns, columns are added to the gridbag to match
  282. * the number of elements in columnWidth.
  283. *
  284. * @serial
  285. * @see #getLayoutDimensions()
  286. */
  287. public int columnWidths[];
  288. /**
  289. * This field holds the overrides to the row minimum
  290. * heights. If this field is non-null the values are
  291. * applied to the gridbag after all of the minimum row
  292. * heights have been calculated.
  293. * If rowHeights has more elements than the number of
  294. * rows, rowa are added to the gridbag to match
  295. * the number of elements in rowHeights.
  296. *
  297. * @serial
  298. * @see #getLayoutDimensions()
  299. */
  300. public int rowHeights[];
  301. /**
  302. * This field holds the overrides to the column weights.
  303. * If this field is non-null the values are
  304. * applied to the gridbag after all of the columns
  305. * weights have been calculated.
  306. * If columnWeights[i] > weight for column i, then
  307. * column i is assigned the weight in columnWeights[i].
  308. * If columnWeights has more elements than the number
  309. * of columns, the excess elements are ignored - they do
  310. * not cause more columns to be created.
  311. *
  312. * @serial
  313. */
  314. public double columnWeights[];
  315. /**
  316. * This field holds the overrides to the row weights.
  317. * If this field is non-null the values are
  318. * applied to the gridbag after all of the rows
  319. * weights have been calculated.
  320. * If rowWeights[i] > weight for row i, then
  321. * row i is assigned the weight in rowWeights[i].
  322. * If rowWeights has more elements than the number
  323. * of rows, the excess elements are ignored - they do
  324. * not cause more rows to be created.
  325. *
  326. * @serial
  327. */
  328. public double rowWeights[];
  329. /**
  330. * Creates a grid bag layout manager.
  331. */
  332. public GridBagLayout () {
  333. comptable = new Hashtable();
  334. defaultConstraints = new GridBagConstraints();
  335. }
  336. /**
  337. * Sets the constraints for the specified component in this layout.
  338. * @param comp the component to be modified.
  339. * @param constraints the constraints to be applied.
  340. */
  341. public void setConstraints(Component comp, GridBagConstraints constraints) {
  342. comptable.put(comp, constraints.clone());
  343. }
  344. /**
  345. * Gets the constraints for the specified component. A copy of
  346. * the actual <code>GridBagConstraints</code> object is returned.
  347. * @param comp the component to be queried.
  348. * @return the constraint for the specified component in this
  349. * grid bag layout; a copy of the actual constraint
  350. * object is returned.
  351. */
  352. public GridBagConstraints getConstraints(Component comp) {
  353. GridBagConstraints constraints = (GridBagConstraints)comptable.get(comp);
  354. if (constraints == null) {
  355. setConstraints(comp, defaultConstraints);
  356. constraints = (GridBagConstraints)comptable.get(comp);
  357. }
  358. return (GridBagConstraints)constraints.clone();
  359. }
  360. /**
  361. * Retrieves the constraints for the specified component.
  362. * The return value is not a copy, but is the actual
  363. * <code>GridBagConstraints</code> object used by the layout mechanism.
  364. * @param comp the component to be queried
  365. * @return the contraints for the specified component.
  366. */
  367. protected GridBagConstraints lookupConstraints(Component comp) {
  368. GridBagConstraints constraints = (GridBagConstraints)comptable.get(comp);
  369. if (constraints == null) {
  370. setConstraints(comp, defaultConstraints);
  371. constraints = (GridBagConstraints)comptable.get(comp);
  372. }
  373. return constraints;
  374. }
  375. /**
  376. * Removes the constraints for the specified component in this layout
  377. * @param comp the component to be modified.
  378. */
  379. private void removeConstraints(Component comp) {
  380. comptable.remove(comp);
  381. }
  382. /**
  383. * Determines the origin of the layout grid.
  384. * Most applications do not call this method directly.
  385. * @return the origin of the cell in the top-left
  386. * corner of the layout grid.
  387. * @since JDK1.1
  388. */
  389. public Point getLayoutOrigin () {
  390. Point origin = new Point(0,0);
  391. if (layoutInfo != null) {
  392. origin.x = layoutInfo.startx;
  393. origin.y = layoutInfo.starty;
  394. }
  395. return origin;
  396. }
  397. /**
  398. * Determines column widths and row heights for the layout grid.
  399. * <p>
  400. * Most applications do not call this method directly.
  401. * @return an array of two arrays, containing the widths
  402. * of the layout columns and
  403. * the heights of the layout rows.
  404. * @since JDK1.1
  405. */
  406. public int [][] getLayoutDimensions () {
  407. if (layoutInfo == null)
  408. return new int[2][0];
  409. int dim[][] = new int [2][];
  410. dim[0] = new int[layoutInfo.width];
  411. dim[1] = new int[layoutInfo.height];
  412. System.arraycopy(layoutInfo.minWidth, 0, dim[0], 0, layoutInfo.width);
  413. System.arraycopy(layoutInfo.minHeight, 0, dim[1], 0, layoutInfo.height);
  414. return dim;
  415. }
  416. /**
  417. * Determines the weights of the layout grid's columns and rows.
  418. * Weights are used to calculate how much a given column or row
  419. * stretches beyond its preferred size, if the layout has extra
  420. * room to fill.
  421. * <p>
  422. * Most applications do not call this method directly.
  423. * @return an array of two arrays, representing the
  424. * horizontal weights of the layout columns
  425. * and the vertical weights of the layout rows.
  426. * @since JDK1.1
  427. */
  428. public double [][] getLayoutWeights () {
  429. if (layoutInfo == null)
  430. return new double[2][0];
  431. double weights[][] = new double [2][];
  432. weights[0] = new double[layoutInfo.width];
  433. weights[1] = new double[layoutInfo.height];
  434. System.arraycopy(layoutInfo.weightX, 0, weights[0], 0, layoutInfo.width);
  435. System.arraycopy(layoutInfo.weightY, 0, weights[1], 0, layoutInfo.height);
  436. return weights;
  437. }
  438. /**
  439. * Determines which cell in the layout grid contains the point
  440. * specified by <code>(x, y)</code>. Each cell is identified
  441. * by its column index (ranging from 0 to the number of columns
  442. * minus 1) and its row index (ranging from 0 to the number of
  443. * rows minus 1).
  444. * <p>
  445. * If the <code>(x, y)</code> point lies
  446. * outside the grid, the following rules are used.
  447. * The column index is returned as zero if <code>x</code> lies to the
  448. * left of the layout, and as the number of columns if <code>x</code> lies
  449. * to the right of the layout. The row index is returned as zero
  450. * if <code>y</code> lies above the layout,
  451. * and as the number of rows if <code>y</code> lies
  452. * below the layout.
  453. * @param x the <i>x</i> coordinate of a point.
  454. * @param y the <i>y</i> coordinate of a point.
  455. * @return an ordered pair of indexes that indicate which cell
  456. * in the layout grid contains the point
  457. * (<i>x</i>, <i>y</i>).
  458. * @since JDK1.1
  459. */
  460. public Point location(int x, int y) {
  461. Point loc = new Point(0,0);
  462. int i, d;
  463. if (layoutInfo == null)
  464. return loc;
  465. d = layoutInfo.startx;
  466. for (i=0; i<layoutInfo.width; i++) {
  467. d += layoutInfo.minWidth[i];
  468. if (d > x)
  469. break;
  470. }
  471. loc.x = i;
  472. d = layoutInfo.starty;
  473. for (i=0; i<layoutInfo.height; i++) {
  474. d += layoutInfo.minHeight[i];
  475. if (d > y)
  476. break;
  477. }
  478. loc.y = i;
  479. return loc;
  480. }
  481. /**
  482. * Adds the specified component with the specified name to the layout.
  483. * @param name the name of the component.
  484. * @param comp the component to be added.
  485. */
  486. public void addLayoutComponent(String name, Component comp) {
  487. }
  488. /**
  489. * Adds the specified component to the layout, using the specified
  490. * constraint object.
  491. * @param comp the component to be added.
  492. * @param constraints an object that determines how
  493. * the component is added to the layout.
  494. */
  495. public void addLayoutComponent(Component comp, Object constraints) {
  496. if (constraints instanceof GridBagConstraints) {
  497. setConstraints(comp, (GridBagConstraints)constraints);
  498. } else if (constraints != null) {
  499. throw new IllegalArgumentException("cannot add to layout: constraint must be a GridBagConstraint");
  500. }
  501. }
  502. /**
  503. * Removes the specified component from this layout.
  504. * <p>
  505. * Most applications do not call this method directly.
  506. * @param comp the component to be removed.
  507. * @see java.awt.Container#remove(java.awt.Component)
  508. * @see java.awt.Container#removeAll()
  509. */
  510. public void removeLayoutComponent(Component comp) {
  511. removeConstraints(comp);
  512. }
  513. /**
  514. * Determines the preferred size of the <code>target</code>
  515. * container using this grid bag layout.
  516. * <p>
  517. * Most applications do not call this method directly.
  518. * @param target the container in which to do the layout.
  519. * @see java.awt.Container#getPreferredSize
  520. */
  521. public Dimension preferredLayoutSize(Container parent) {
  522. GridBagLayoutInfo info = GetLayoutInfo(parent, PREFERREDSIZE);
  523. return GetMinSize(parent, info);
  524. }
  525. /**
  526. * Determines the minimum size of the <code>target</code> container
  527. * using this grid bag layout.
  528. * <p>
  529. * Most applications do not call this method directly.
  530. * @param target the container in which to do the layout.
  531. * @see java.awt.Container#doLayout
  532. */
  533. public Dimension minimumLayoutSize(Container parent) {
  534. GridBagLayoutInfo info = GetLayoutInfo(parent, MINSIZE);
  535. return GetMinSize(parent, info);
  536. }
  537. /**
  538. * Returns the maximum dimensions for this layout given the components
  539. * in the specified target container.
  540. * @param target the component which needs to be laid out
  541. * @see Container
  542. * @see #minimumLayoutSize(Container)
  543. * @see #preferredLayoutSize(Container)
  544. */
  545. public Dimension maximumLayoutSize(Container target) {
  546. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  547. }
  548. /**
  549. * Returns the alignment along the x axis. This specifies how
  550. * the component would like to be aligned relative to other
  551. * components. The value should be a number between 0 and 1
  552. * where 0 represents alignment along the origin, 1 is aligned
  553. * the furthest away from the origin, 0.5 is centered, etc.
  554. */
  555. public float getLayoutAlignmentX(Container parent) {
  556. return 0.5f;
  557. }
  558. /**
  559. * Returns the alignment along the y axis. This specifies how
  560. * the component would like to be aligned relative to other
  561. * components. The value should be a number between 0 and 1
  562. * where 0 represents alignment along the origin, 1 is aligned
  563. * the furthest away from the origin, 0.5 is centered, etc.
  564. */
  565. public float getLayoutAlignmentY(Container parent) {
  566. return 0.5f;
  567. }
  568. /**
  569. * Invalidates the layout, indicating that if the layout manager
  570. * has cached information it should be discarded.
  571. */
  572. public void invalidateLayout(Container target) {
  573. }
  574. /**
  575. * Lays out the specified container using this grid bag layout.
  576. * This method reshapes components in the specified container in
  577. * order to satisfy the contraints of this <code>GridBagLayout</code>
  578. * object.
  579. * <p>
  580. * Most applications do not call this method directly.
  581. * @param parent the container in which to do the layout.
  582. * @see java.awt.Container
  583. * @see java.awt.Container#doLayout
  584. */
  585. public void layoutContainer(Container parent) {
  586. ArrangeGrid(parent);
  587. }
  588. /**
  589. * Returns a string representation of this grid bag layout's values.
  590. * @return a string representation of this grid bag layout.
  591. */
  592. public String toString() {
  593. return getClass().getName();
  594. }
  595. /**
  596. * Print the layout information. Useful for debugging.
  597. */
  598. /* DEBUG
  599. *
  600. * protected void DumpLayoutInfo(GridBagLayoutInfo s) {
  601. * int x;
  602. *
  603. * System.out.println("Col\tWidth\tWeight");
  604. * for (x=0; x<s.width; x++) {
  605. * System.out.println(x + "\t" +
  606. * s.minWidth[x] + "\t" +
  607. * s.weightX[x]);
  608. * }
  609. * System.out.println("Row\tHeight\tWeight");
  610. * for (x=0; x<s.height; x++) {
  611. * System.out.println(x + "\t" +
  612. * s.minHeight[x] + "\t" +
  613. * s.weightY[x]);
  614. * }
  615. * }
  616. */
  617. /**
  618. * Print the layout constraints. Useful for debugging.
  619. */
  620. /* DEBUG
  621. *
  622. * protected void DumpConstraints(GridBagConstraints constraints) {
  623. * System.out.println(
  624. * "wt " +
  625. * constraints.weightx +
  626. * " " +
  627. * constraints.weighty +
  628. * ", " +
  629. *
  630. * "box " +
  631. * constraints.gridx +
  632. * " " +
  633. * constraints.gridy +
  634. * " " +
  635. * constraints.gridwidth +
  636. * " " +
  637. * constraints.gridheight +
  638. * ", " +
  639. *
  640. * "min " +
  641. * constraints.minWidth +
  642. * " " +
  643. * constraints.minHeight +
  644. * ", " +
  645. *
  646. * "pad " +
  647. * constraints.insets.bottom +
  648. * " " +
  649. * constraints.insets.left +
  650. * " " +
  651. * constraints.insets.right +
  652. * " " +
  653. * constraints.insets.top +
  654. * " " +
  655. * constraints.ipadx +
  656. * " " +
  657. * constraints.ipady);
  658. * }
  659. */
  660. /*
  661. * Fill in an instance of the above structure for the current set
  662. * of managed children. This requires three passes through the
  663. * set of children:
  664. *
  665. * 1) Figure out the dimensions of the layout grid
  666. * 2) Determine which cells the components occupy
  667. * 3) Distribute the weights and min sizes amoung the rows/columns.
  668. *
  669. * This also caches the minsizes for all the children when they are
  670. * first encountered (so subsequent loops don't need to ask again).
  671. */
  672. protected GridBagLayoutInfo GetLayoutInfo(Container parent, int sizeflag) {
  673. synchronized (parent.getTreeLock()) {
  674. GridBagLayoutInfo r = new GridBagLayoutInfo();
  675. Component comp;
  676. GridBagConstraints constraints;
  677. Dimension d;
  678. Component components[] = parent.getComponents();
  679. int compindex, i, j, k, px, py, pixels_diff, nextSize;
  680. int curX, curY, curWidth, curHeight, curRow, curCol;
  681. double weight_diff, weight, start, size;
  682. int xMax[], yMax[];
  683. /*
  684. * Pass #1
  685. *
  686. * Figure out the dimensions of the layout grid (use a value of 1 for
  687. * zero or negative widths and heights).
  688. */
  689. r.width = r.height = 0;
  690. curRow = curCol = -1;
  691. xMax = new int[MAXGRIDSIZE];
  692. yMax = new int[MAXGRIDSIZE];
  693. for (compindex = 0 ; compindex < components.length ; compindex++) {
  694. comp = components[compindex];
  695. if (!comp.isVisible())
  696. continue;
  697. constraints = lookupConstraints(comp);
  698. curX = constraints.gridx;
  699. curY = constraints.gridy;
  700. curWidth = constraints.gridwidth;
  701. if (curWidth <= 0)
  702. curWidth = 1;
  703. curHeight = constraints.gridheight;
  704. if (curHeight <= 0)
  705. curHeight = 1;
  706. /* If x or y is negative, then use relative positioning: */
  707. if (curX < 0 && curY < 0) {
  708. if (curRow >= 0)
  709. curY = curRow;
  710. else if (curCol >= 0)
  711. curX = curCol;
  712. else
  713. curY = 0;
  714. }
  715. if (curX < 0) {
  716. px = 0;
  717. for (i = curY; i < (curY + curHeight); i++)
  718. px = Math.max(px, xMax[i]);
  719. curX = px - curX - 1;
  720. if(curX < 0)
  721. curX = 0;
  722. }
  723. else if (curY < 0) {
  724. py = 0;
  725. for (i = curX; i < (curX + curWidth); i++)
  726. py = Math.max(py, yMax[i]);
  727. curY = py - curY - 1;
  728. if(curY < 0)
  729. curY = 0;
  730. }
  731. /* Adjust the grid width and height */
  732. for (px = curX + curWidth; r.width < px; r.width++);
  733. for (py = curY + curHeight; r.height < py; r.height++);
  734. /* Adjust the xMax and yMax arrays */
  735. for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
  736. for (i = curY; i < (curY + curHeight); i++) { xMax[i] = px; }
  737. /* Cache the current slave's size. */
  738. if (sizeflag == PREFERREDSIZE)
  739. d = comp.getPreferredSize();
  740. else
  741. d = comp.getMinimumSize();
  742. constraints.minWidth = d.width;
  743. constraints.minHeight = d.height;
  744. /* Zero width and height must mean that this is the last item (or
  745. * else something is wrong). */
  746. if (constraints.gridheight == 0 && constraints.gridwidth == 0)
  747. curRow = curCol = -1;
  748. /* Zero width starts a new row */
  749. if (constraints.gridheight == 0 && curRow < 0)
  750. curCol = curX + curWidth;
  751. /* Zero height starts a new column */
  752. else if (constraints.gridwidth == 0 && curCol < 0)
  753. curRow = curY + curHeight;
  754. }
  755. /*
  756. * Apply minimum row/column dimensions
  757. */
  758. if (columnWidths != null && r.width < columnWidths.length)
  759. r.width = columnWidths.length;
  760. if (rowHeights != null && r.height < rowHeights.length)
  761. r.height = rowHeights.length;
  762. /*
  763. * Pass #2
  764. *
  765. * Negative values for gridX are filled in with the current x value.
  766. * Negative values for gridY are filled in with the current y value.
  767. * Negative or zero values for gridWidth and gridHeight end the current
  768. * row or column, respectively.
  769. */
  770. curRow = curCol = -1;
  771. xMax = new int[MAXGRIDSIZE];
  772. yMax = new int[MAXGRIDSIZE];
  773. for (compindex = 0 ; compindex < components.length ; compindex++) {
  774. comp = components[compindex];
  775. if (!comp.isVisible())
  776. continue;
  777. constraints = lookupConstraints(comp);
  778. curX = constraints.gridx;
  779. curY = constraints.gridy;
  780. curWidth = constraints.gridwidth;
  781. curHeight = constraints.gridheight;
  782. /* If x or y is negative, then use relative positioning: */
  783. if (curX < 0 && curY < 0) {
  784. if(curRow >= 0)
  785. curY = curRow;
  786. else if(curCol >= 0)
  787. curX = curCol;
  788. else
  789. curY = 0;
  790. }
  791. if (curX < 0) {
  792. if (curHeight <= 0) {
  793. curHeight += r.height - curY;
  794. if (curHeight < 1)
  795. curHeight = 1;
  796. }
  797. px = 0;
  798. for (i = curY; i < (curY + curHeight); i++)
  799. px = Math.max(px, xMax[i]);
  800. curX = px - curX - 1;
  801. if(curX < 0)
  802. curX = 0;
  803. }
  804. else if (curY < 0) {
  805. if (curWidth <= 0) {
  806. curWidth += r.width - curX;
  807. if (curWidth < 1)
  808. curWidth = 1;
  809. }
  810. py = 0;
  811. for (i = curX; i < (curX + curWidth); i++)
  812. py = Math.max(py, yMax[i]);
  813. curY = py - curY - 1;
  814. if(curY < 0)
  815. curY = 0;
  816. }
  817. if (curWidth <= 0) {
  818. curWidth += r.width - curX;
  819. if (curWidth < 1)
  820. curWidth = 1;
  821. }
  822. if (curHeight <= 0) {
  823. curHeight += r.height - curY;
  824. if (curHeight < 1)
  825. curHeight = 1;
  826. }
  827. px = curX + curWidth;
  828. py = curY + curHeight;
  829. for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
  830. for (i = curY; i < (curY + curHeight); i++) { xMax[i] = px; }
  831. /* Make negative sizes start a new row/column */
  832. if (constraints.gridheight == 0 && constraints.gridwidth == 0)
  833. curRow = curCol = -1;
  834. if (constraints.gridheight == 0 && curRow < 0)
  835. curCol = curX + curWidth;
  836. else if (constraints.gridwidth == 0 && curCol < 0)
  837. curRow = curY + curHeight;
  838. /* Assign the new values to the gridbag slave */
  839. constraints.tempX = curX;
  840. constraints.tempY = curY;
  841. constraints.tempWidth = curWidth;
  842. constraints.tempHeight = curHeight;
  843. }
  844. /*
  845. * Apply minimum row/column dimensions and weights
  846. */
  847. if (columnWidths != null)
  848. System.arraycopy(columnWidths, 0, r.minWidth, 0, columnWidths.length);
  849. if (rowHeights != null)
  850. System.arraycopy(rowHeights, 0, r.minHeight, 0, rowHeights.length);
  851. if (columnWeights != null)
  852. System.arraycopy(columnWeights, 0, r.weightX, 0, columnWeights.length);
  853. if (rowWeights != null)
  854. System.arraycopy(rowWeights, 0, r.weightY, 0, rowWeights.length);
  855. /*
  856. * Pass #3
  857. *
  858. * Distribute the minimun widths and weights:
  859. */
  860. nextSize = Integer.MAX_VALUE;
  861. for (i = 1;
  862. i != Integer.MAX_VALUE;
  863. i = nextSize, nextSize = Integer.MAX_VALUE) {
  864. for (compindex = 0 ; compindex < components.length ; compindex++) {
  865. comp = components[compindex];
  866. if (!comp.isVisible())
  867. continue;
  868. constraints = lookupConstraints(comp);
  869. if (constraints.tempWidth == i) {
  870. px = constraints.tempX + constraints.tempWidth; /* right column */
  871. /*
  872. * Figure out if we should use this slave\'s weight. If the weight
  873. * is less than the total weight spanned by the width of the cell,
  874. * then discard the weight. Otherwise split the difference
  875. * according to the existing weights.
  876. */
  877. weight_diff = constraints.weightx;
  878. for (k = constraints.tempX; k < px; k++)
  879. weight_diff -= r.weightX[k];
  880. if (weight_diff > 0.0) {
  881. weight = 0.0;
  882. for (k = constraints.tempX; k < px; k++)
  883. weight += r.weightX[k];
  884. for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
  885. double wt = r.weightX[k];
  886. double dx = (wt * weight_diff) / weight;
  887. r.weightX[k] += dx;
  888. weight_diff -= dx;
  889. weight -= wt;
  890. }
  891. /* Assign the remainder to the rightmost cell */
  892. r.weightX[px-1] += weight_diff;
  893. }
  894. /*
  895. * Calculate the minWidth array values.
  896. * First, figure out how wide the current slave needs to be.
  897. * Then, see if it will fit within the current minWidth values.
  898. * If it will not fit, add the difference according to the
  899. * weightX array.
  900. */
  901. pixels_diff =
  902. constraints.minWidth + constraints.ipadx +
  903. constraints.insets.left + constraints.insets.right;
  904. for (k = constraints.tempX; k < px; k++)
  905. pixels_diff -= r.minWidth[k];
  906. if (pixels_diff > 0) {
  907. weight = 0.0;
  908. for (k = constraints.tempX; k < px; k++)
  909. weight += r.weightX[k];
  910. for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
  911. double wt = r.weightX[k];
  912. int dx = (int)((wt * ((double)pixels_diff)) / weight);
  913. r.minWidth[k] += dx;
  914. pixels_diff -= dx;
  915. weight -= wt;
  916. }
  917. /* Any leftovers go into the rightmost cell */
  918. r.minWidth[px-1] += pixels_diff;
  919. }
  920. }
  921. else if (constraints.tempWidth > i && constraints.tempWidth < nextSize)
  922. nextSize = constraints.tempWidth;
  923. if (constraints.tempHeight == i) {
  924. py = constraints.tempY + constraints.tempHeight; /* bottom row */
  925. /*
  926. * Figure out if we should use this slave\'s weight. If the weight
  927. * is less than the total weight spanned by the height of the cell,
  928. * then discard the weight. Otherwise split it the difference
  929. * according to the existing weights.
  930. */
  931. weight_diff = constraints.weighty;
  932. for (k = constraints.tempY; k < py; k++)
  933. weight_diff -= r.weightY[k];
  934. if (weight_diff > 0.0) {
  935. weight = 0.0;
  936. for (k = constraints.tempY; k < py; k++)
  937. weight += r.weightY[k];
  938. for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
  939. double wt = r.weightY[k];
  940. double dy = (wt * weight_diff) / weight;
  941. r.weightY[k] += dy;
  942. weight_diff -= dy;
  943. weight -= wt;
  944. }
  945. /* Assign the remainder to the bottom cell */
  946. r.weightY[py-1] += weight_diff;
  947. }
  948. /*
  949. * Calculate the minHeight array values.
  950. * First, figure out how tall the current slave needs to be.
  951. * Then, see if it will fit within the current minHeight values.
  952. * If it will not fit, add the difference according to the
  953. * weightY array.
  954. */
  955. pixels_diff =
  956. constraints.minHeight + constraints.ipady +
  957. constraints.insets.top + constraints.insets.bottom;
  958. for (k = constraints.tempY; k < py; k++)
  959. pixels_diff -= r.minHeight[k];
  960. if (pixels_diff > 0) {
  961. weight = 0.0;
  962. for (k = constraints.tempY; k < py; k++)
  963. weight += r.weightY[k];
  964. for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
  965. double wt = r.weightY[k];
  966. int dy = (int)((wt * ((double)pixels_diff)) / weight);
  967. r.minHeight[k] += dy;
  968. pixels_diff -= dy;
  969. weight -= wt;
  970. }
  971. /* Any leftovers go into the bottom cell */
  972. r.minHeight[py-1] += pixels_diff;
  973. }
  974. }
  975. else if (constraints.tempHeight > i &&
  976. constraints.tempHeight < nextSize)
  977. nextSize = constraints.tempHeight;
  978. }
  979. }
  980. return r;
  981. }
  982. }
  983. /*
  984. * Adjusts the x, y, width, and height fields to the correct
  985. * values depending on the constraint geometry and pads.
  986. */
  987. protected void AdjustForGravity(GridBagConstraints constraints,
  988. Rectangle r) {
  989. int diffx, diffy;
  990. r.x += constraints.insets.left;
  991. r.width -= (constraints.insets.left + constraints.insets.right);
  992. r.y += constraints.insets.top;
  993. r.height -= (constraints.insets.top + constraints.insets.bottom);
  994. diffx = 0;
  995. if ((constraints.fill != GridBagConstraints.HORIZONTAL &&
  996. constraints.fill != GridBagConstraints.BOTH)
  997. && (r.width > (constraints.minWidth + constraints.ipadx))) {
  998. diffx = r.width - (constraints.minWidth + constraints.ipadx);
  999. r.width = constraints.minWidth + constraints.ipadx;
  1000. }
  1001. diffy = 0;
  1002. if ((constraints.fill != GridBagConstraints.VERTICAL &&
  1003. constraints.fill != GridBagConstraints.BOTH)
  1004. && (r.height > (constraints.minHeight + constraints.ipady))) {
  1005. diffy = r.height - (constraints.minHeight + constraints.ipady);
  1006. r.height = constraints.minHeight + constraints.ipady;
  1007. }
  1008. switch (constraints.anchor) {
  1009. case GridBagConstraints.CENTER:
  1010. r.x += diffx2;
  1011. r.y += diffy2;
  1012. break;
  1013. case GridBagConstraints.NORTH:
  1014. r.x += diffx2;
  1015. break;
  1016. case GridBagConstraints.NORTHEAST:
  1017. r.x += diffx;
  1018. break;
  1019. case GridBagConstraints.EAST:
  1020. r.x += diffx;
  1021. r.y += diffy2;
  1022. break;
  1023. case GridBagConstraints.SOUTHEAST:
  1024. r.x += diffx;
  1025. r.y += diffy;
  1026. break;
  1027. case GridBagConstraints.SOUTH:
  1028. r.x += diffx2;
  1029. r.y += diffy;
  1030. break;
  1031. case GridBagConstraints.SOUTHWEST:
  1032. r.y += diffy;
  1033. break;
  1034. case GridBagConstraints.WEST:
  1035. r.y += diffy2;
  1036. break;
  1037. case GridBagConstraints.NORTHWEST:
  1038. break;
  1039. default:
  1040. throw new IllegalArgumentException("illegal anchor value");
  1041. }
  1042. }
  1043. /*
  1044. * Figure out the minimum size of the
  1045. * master based on the information from GetLayoutInfo()
  1046. */
  1047. protected Dimension GetMinSize(Container parent, GridBagLayoutInfo info) {
  1048. Dimension d = new Dimension();
  1049. int i, t;
  1050. Insets insets = parent.getInsets();
  1051. t = 0;
  1052. for(i = 0; i < info.width; i++)
  1053. t += info.minWidth[i];
  1054. d.width = t + insets.left + insets.right;
  1055. t = 0;
  1056. for(i = 0; i < info.height; i++)
  1057. t += info.minHeight[i];
  1058. d.height = t + insets.top + insets.bottom;
  1059. return d;
  1060. }
  1061. /*
  1062. * Lay out the grid
  1063. */
  1064. protected void ArrangeGrid(Container parent) {
  1065. Component comp;
  1066. int compindex;
  1067. GridBagConstraints constraints;
  1068. Insets insets = parent.getInsets();
  1069. Component components[] = parent.getComponents();
  1070. Dimension d;
  1071. Rectangle r = new Rectangle();
  1072. int i, diffw, diffh;
  1073. double weight;
  1074. GridBagLayoutInfo info;
  1075. /*
  1076. * If the parent has no slaves anymore, then don't do anything
  1077. * at all: just leave the parent's size as-is.
  1078. */
  1079. if (components.length == 0 &&
  1080. (columnWidths == null || columnWidths.length == 0) &&
  1081. (rowHeights == null || rowHeights.length == 0)) {
  1082. return;
  1083. }
  1084. /*
  1085. * Pass #1: scan all the slaves to figure out the total amount
  1086. * of space needed.
  1087. */
  1088. info = GetLayoutInfo(parent, PREFERREDSIZE);
  1089. d = GetMinSize(parent, info);
  1090. if (parent.width < d.width || parent.height < d.height) {
  1091. info = GetLayoutInfo(parent, MINSIZE);
  1092. d = GetMinSize(parent, info);
  1093. }
  1094. layoutInfo = info;
  1095. r.width = d.width;
  1096. r.height = d.height;
  1097. /*
  1098. * DEBUG
  1099. *
  1100. * DumpLayoutInfo(info);
  1101. * for (compindex = 0 ; compindex < components.length ; compindex++) {
  1102. * comp = components[compindex];
  1103. * if (!comp.isVisible())
  1104. * continue;
  1105. * constraints = lookupConstraints(comp);
  1106. * DumpConstraints(constraints);
  1107. * }
  1108. * System.out.println("minSize " + r.width + " " + r.height);
  1109. */
  1110. /*
  1111. * If the current dimensions of the window don't match the desired
  1112. * dimensions, then adjust the minWidth and minHeight arrays
  1113. * according to the weights.
  1114. */
  1115. diffw = parent.width - r.width;
  1116. if (diffw != 0) {
  1117. weight = 0.0;
  1118. for (i = 0; i < info.width; i++)
  1119. weight += info.weightX[i];
  1120. if (weight > 0.0) {
  1121. for (i = 0; i < info.width; i++) {
  1122. int dx = (int)(( ((double)diffw) * info.weightX[i]) / weight);
  1123. info.minWidth[i] += dx;
  1124. r.width += dx;
  1125. if (info.minWidth[i] < 0) {
  1126. r.width -= info.minWidth[i];
  1127. info.minWidth[i] = 0;
  1128. }
  1129. }
  1130. }
  1131. diffw = parent.width - r.width;
  1132. }
  1133. else {
  1134. diffw = 0;
  1135. }
  1136. diffh = parent.height - r.height;
  1137. if (diffh != 0) {
  1138. weight = 0.0;
  1139. for (i = 0; i < info.height; i++)
  1140. weight += info.weightY[i];
  1141. if (weight > 0.0) {
  1142. for (i = 0; i < info.height; i++) {
  1143. int dy = (int)(( ((double)diffh) * info.weightY[i]) / weight);
  1144. info.minHeight[i] += dy;
  1145. r.height += dy;
  1146. if (info.minHeight[i] < 0) {
  1147. r.height -= info.minHeight[i];
  1148. info.minHeight[i] = 0;
  1149. }
  1150. }
  1151. }
  1152. diffh = parent.height - r.height;
  1153. }
  1154. else {
  1155. diffh = 0;
  1156. }
  1157. /*
  1158. * DEBUG
  1159. *
  1160. * System.out.println("Re-adjusted:");
  1161. * DumpLayoutInfo(info);
  1162. */
  1163. /*
  1164. * Now do the actual layout of the slaves using the layout information
  1165. * that has been collected.
  1166. */
  1167. info.startx = diffw2 + insets.left;
  1168. info.starty = diffh2 + insets.top;
  1169. for (compindex = 0 ; compindex < components.length ; compindex++) {
  1170. comp = components[compindex];
  1171. if (!comp.isVisible())
  1172. continue;
  1173. constraints = lookupConstraints(comp);
  1174. r.x = info.startx;
  1175. for(i = 0; i < constraints.tempX; i++)
  1176. r.x += info.minWidth[i];
  1177. r.y = info.starty;
  1178. for(i = 0; i < constraints.tempY; i++)
  1179. r.y += info.minHeight[i];
  1180. r.width = 0;
  1181. for(i = constraints.tempX;
  1182. i < (constraints.tempX + constraints.tempWidth);
  1183. i++) {
  1184. r.width += info.minWidth[i];
  1185. }
  1186. r.height = 0;
  1187. for(i = constraints.tempY;
  1188. i < (constraints.tempY + constraints.tempHeight);
  1189. i++) {
  1190. r.height += info.minHeight[i];
  1191. }
  1192. AdjustForGravity(constraints, r);
  1193. /*
  1194. * If the window is too small to be interesting then
  1195. * unmap it. Otherwise configure it and then make sure
  1196. * it's mapped.
  1197. */
  1198. if ((r.width <= 0) || (r.height <= 0)) {
  1199. comp.setBounds(0, 0, 0, 0);
  1200. }
  1201. else {
  1202. if (comp.x != r.x || comp.y != r.y ||
  1203. comp.width != r.width || comp.height != r.height) {
  1204. comp.setBounds(r.x, r.y, r.width, r.height);
  1205. }
  1206. }
  1207. }
  1208. }
  1209. }