1. /*
  2. * @(#)BoxLayout.java 1.24 00/02/02
  3. *
  4. * Copyright 1997-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 javax.swing;
  11. import java.awt.*;
  12. import java.io.Serializable;
  13. import java.io.PrintStream;
  14. /**
  15. * A layout manager that allows multiple components to be layed out either
  16. * vertically or horizontally. The components will not wrap so, for
  17. * example, a vertical arrangement of components will stay vertically
  18. * arranged when the frame is resized.
  19. * <TABLE ALIGN="RIGHT" BORDER="0">
  20. * <TR>
  21. * <TD ALIGN="CENTER">
  22. * <P ALIGN="CENTER"><IMG SRC="doc-files/BoxLayout-1.gif" WIDTH="191" HEIGHT="201" ALIGN="BOTTOM" BORDER="0">
  23. * </TD>
  24. * </TR>
  25. * </TABLE>
  26. * <p>
  27. * Nesting multiple panels with different combinations of horizontal and
  28. * vertical gives an effect similar to GridBagLayout, without the
  29. * complexity. The diagram shows two panels arranged horizontally, each
  30. * of which contains 3 components arranged vertically.
  31. * <p>
  32. * The Box container uses BoxLayout (unlike JPanel, which defaults to flow
  33. * layout). You can nest multiple boxes and add components to them to get
  34. * the arrangement you want.
  35. * <p>
  36. * The BoxLayout manager that places each of its managed components
  37. * from left to right or from top to bottom.
  38. * When you create a BoxLayout, you specify whether its major axis is
  39. * the X axis (which means left to right placement) or Y axis (top to
  40. * bottom placement). Components are arranged from left to right (or
  41. * top to bottom), in the same order as they were added to the container.
  42. * <p>
  43. * Instead of using BoxLayout directly, many programs use the Box class.
  44. * The Box class provides a lightweight container that uses a BoxLayout.
  45. * Box also provides handy methods to help you use BoxLayout well.
  46. * <p>
  47. * BoxLayout attempts to arrange components
  48. * at their preferred widths (for left to right layout)
  49. * or heights (for top to bottom layout).
  50. * For a left to right layout,
  51. * if not all the components are the same height,
  52. * BoxLayout attempts to make all the components
  53. * as high as the highest component.
  54. * If that's not possible for a particular component,
  55. * then BoxLayout aligns that component vertically,
  56. * according to the component's Y alignment.
  57. * By default, a component has an Y alignment of 0.5,
  58. * which means that the vertical center of the component
  59. * should have the same Y coordinate as
  60. * the vertical centers of other components with 0.5 Y alignment.
  61. * <p>
  62. * Similarly, for a vertical layout,
  63. * BoxLayout attempts to make all components in the column
  64. * as wide as the widest component;
  65. * if that fails, it aligns them horizontally
  66. * according to their X alignments.
  67. * <p>
  68. * <strong>Warning:</strong>
  69. * Serialized objects of this class will not be compatible with
  70. * future Swing releases. The current serialization support is appropriate
  71. * for short term storage or RMI between applications running the same
  72. * version of Swing. A future release of Swing will provide support for
  73. * long term persistence.
  74. *
  75. * @see Box
  76. * @see Component#getAlignmentX
  77. * @see Component#getAlignmentY
  78. *
  79. * @author Timothy Prinzing
  80. * @version 1.24 02/02/00
  81. */
  82. public class BoxLayout implements LayoutManager2, Serializable {
  83. /**
  84. * Specifies that components should be laid out left to right.
  85. */
  86. public static final int X_AXIS = 0;
  87. /**
  88. * Specifies that components should be laid out top to bottom.
  89. */
  90. public static final int Y_AXIS = 1;
  91. /**
  92. * Creates a layout manager that will lay out components either
  93. * left to right or
  94. * top to bottom,
  95. * as specified in the <code>axis</code> parameter.
  96. *
  97. * @param target the container that needs to be laid out
  98. * @param axis the axis to lay out components along.
  99. * For left-to-right layout,
  100. * specify <code>BoxLayout.X_AXIS</code>
  101. * for top-to-bottom layout,
  102. * specify <code>BoxLayout.Y_AXIS</code>
  103. *
  104. * @exception AWTError if the value of <code>axis</code> is invalid
  105. */
  106. public BoxLayout(Container target, int axis) {
  107. if (axis != X_AXIS && axis != Y_AXIS) {
  108. throw new AWTError("Invalid axis");
  109. }
  110. this.axis = axis;
  111. this.target = target;
  112. }
  113. /**
  114. * Constructs a BoxLayout that
  115. * produces debugging messages.
  116. *
  117. * @param target the container that needs to be laid out
  118. * @param axis the axis to lay out components along; can be either
  119. * <code>BoxLayout.X_AXIS</code>
  120. * or <code>BoxLayout.Y_AXIS</code>
  121. * @param dbg the stream to which debugging messages should be sent,
  122. * null if none
  123. */
  124. BoxLayout(Container target, int axis, PrintStream dbg) {
  125. this(target, axis);
  126. this.dbg = dbg;
  127. }
  128. /**
  129. * Indicates that a child has changed its layout related information,
  130. * and thus any cached calculations should be flushed.
  131. *
  132. * @param target the affected container
  133. *
  134. * @exception AWTError if the target isn't the container specified to the
  135. * BoxLayout constructor
  136. */
  137. public void invalidateLayout(Container target) {
  138. checkContainer(target);
  139. xChildren = null;
  140. yChildren = null;
  141. xTotal = null;
  142. yTotal = null;
  143. }
  144. /**
  145. * Not used by this class.
  146. *
  147. * @param name the name of the component
  148. * @param comp the component
  149. */
  150. public void addLayoutComponent(String name, Component comp) {
  151. }
  152. /**
  153. * Not used by this class.
  154. *
  155. * @param comp the component
  156. */
  157. public void removeLayoutComponent(Component comp) {
  158. }
  159. /**
  160. * Not used by this class.
  161. *
  162. * @param comp the component
  163. * @param constraints constraints
  164. */
  165. public void addLayoutComponent(Component comp, Object constraints) {
  166. }
  167. /**
  168. * Returns the preferred dimensions for this layout, given the components
  169. * in the specified target container.
  170. *
  171. * @param target the container that needs to be laid out
  172. * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  173. * @exception AWTError if the target isn't the container specified to the
  174. * BoxLayout constructor
  175. * @see Container
  176. * @see #minimumLayoutSize
  177. * @see #maximumLayoutSize
  178. */
  179. public Dimension preferredLayoutSize(Container target) {
  180. checkContainer(target);
  181. checkRequests();
  182. Dimension size = new Dimension(xTotal.preferred, yTotal.preferred);
  183. Insets insets = target.getInsets();
  184. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  185. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  186. return size;
  187. }
  188. /**
  189. * Returns the minimum dimensions needed to lay out the components
  190. * contained in the specified target container.
  191. *
  192. * @param target the container that needs to be laid out
  193. * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  194. * @exception AWTError if the target isn't the container specified to the
  195. * BoxLayout constructor
  196. * @see #preferredLayoutSize
  197. * @see #maximumLayoutSize
  198. */
  199. public Dimension minimumLayoutSize(Container target) {
  200. checkContainer(target);
  201. checkRequests();
  202. Dimension size = new Dimension(xTotal.minimum, yTotal.minimum);
  203. Insets insets = target.getInsets();
  204. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  205. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  206. return size;
  207. }
  208. /**
  209. * Returns the maximum dimensions the target container can use
  210. * to lay out the components it contains.
  211. *
  212. * @param target the container that needs to be laid out
  213. * @return the dimenions >= 0 && <= Integer.MAX_VALUE
  214. * @exception AWTError if the target isn't the container specified to the
  215. * BoxLayout constructor
  216. * @see #preferredLayoutSize
  217. * @see #minimumLayoutSize
  218. */
  219. public Dimension maximumLayoutSize(Container target) {
  220. checkContainer(target);
  221. checkRequests();
  222. Dimension size = new Dimension(xTotal.maximum, yTotal.maximum);
  223. Insets insets = target.getInsets();
  224. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  225. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  226. return size;
  227. }
  228. /**
  229. * Returns the alignment along the X axis for the container.
  230. * If the box is horizontal, the default
  231. * alignment will be returned. Otherwise, the alignment needed
  232. * to place the children along the X axis will be returned.
  233. *
  234. * @param target the container
  235. * @return the alignment >= 0.0f && <= 1.0f
  236. * @exception AWTError if the target isn't the container specified to the
  237. * BoxLayout constructor
  238. */
  239. public float getLayoutAlignmentX(Container target) {
  240. checkContainer(target);
  241. checkRequests();
  242. return xTotal.alignment;
  243. }
  244. /**
  245. * Returns the alignment along the Y axis for the container.
  246. * If the box is vertical, the default
  247. * alignment will be returned. Otherwise, the alignment needed
  248. * to place the children along the Y axis will be returned.
  249. *
  250. * @param target the container
  251. * @return the alignment >= 0.0f && <= 1.0f
  252. * @exception AWTError if the target isn't the container specified to the
  253. * BoxLayout constructor
  254. */
  255. public float getLayoutAlignmentY(Container target) {
  256. checkContainer(target);
  257. checkRequests();
  258. return yTotal.alignment;
  259. }
  260. /**
  261. * Called by the AWT <!-- XXX CHECK! --> when the specified container
  262. * needs to be laid out.
  263. *
  264. * @param target the container to lay out
  265. *
  266. * @exception AWTError if the target isn't the container specified to the
  267. * BoxLayout constructor
  268. */
  269. public void layoutContainer(Container target) {
  270. checkContainer(target);
  271. checkRequests();
  272. int nChildren = target.getComponentCount();
  273. int[] xOffsets = new int[nChildren];
  274. int[] xSpans = new int[nChildren];
  275. int[] yOffsets = new int[nChildren];
  276. int[] ySpans = new int[nChildren];
  277. // determine the child placements
  278. Dimension alloc = target.getSize();
  279. Insets in = target.getInsets();
  280. alloc.width -= in.left + in.right;
  281. alloc.height -= in.top + in.bottom;
  282. if (axis == X_AXIS) {
  283. SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
  284. xChildren, xOffsets,
  285. xSpans);
  286. SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
  287. yChildren, yOffsets,
  288. ySpans);
  289. } else {
  290. SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
  291. xChildren, xOffsets,
  292. xSpans);
  293. SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
  294. yChildren, yOffsets,
  295. ySpans);
  296. }
  297. // flush changes to the container
  298. for (int i = 0; i < nChildren; i++) {
  299. Component c = target.getComponent(i);
  300. c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
  301. (int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
  302. xSpans[i], ySpans[i]);
  303. }
  304. if (dbg != null) {
  305. for (int i = 0; i < nChildren; i++) {
  306. Component c = target.getComponent(i);
  307. dbg.println(c.toString());
  308. dbg.println("X: " + xChildren[i]);
  309. dbg.println("Y: " + yChildren[i]);
  310. }
  311. }
  312. }
  313. void checkContainer(Container target) {
  314. if (this.target != target) {
  315. throw new AWTError("BoxLayout can't be shared");
  316. }
  317. }
  318. void checkRequests() {
  319. if (xChildren == null || yChildren == null) {
  320. // The requests have been invalidated... recalculate
  321. // the request information.
  322. int n = target.getComponentCount();
  323. xChildren = new SizeRequirements[n];
  324. yChildren = new SizeRequirements[n];
  325. for (int i = 0; i < n; i++) {
  326. Component c = target.getComponent(i);
  327. if (!c.isVisible()) {
  328. xChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentX());
  329. yChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentY());
  330. continue;
  331. }
  332. Dimension min = c.getMinimumSize();
  333. Dimension typ = c.getPreferredSize();
  334. Dimension max = c.getMaximumSize();
  335. xChildren[i] = new SizeRequirements(min.width, typ.width,
  336. max.width,
  337. c.getAlignmentX());
  338. yChildren[i] = new SizeRequirements(min.height, typ.height,
  339. max.height,
  340. c.getAlignmentY());
  341. }
  342. if (axis == X_AXIS) {
  343. xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
  344. yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
  345. } else {
  346. xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
  347. yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
  348. }
  349. }
  350. }
  351. private int axis;
  352. private Container target;
  353. private transient SizeRequirements[] xChildren;
  354. private transient SizeRequirements[] yChildren;
  355. private transient SizeRequirements xTotal;
  356. private transient SizeRequirements yTotal;
  357. private transient PrintStream dbg;
  358. }