1. /*
  2. * @(#)SizeRequirements.java 1.25 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.io.Serializable;
  10. /**
  11. * For the convenience of layout managers,
  12. * calculates information about the size and position of components.
  13. * All size and position calculation methods are class methods
  14. * that take arrays of SizeRequirements as arguments.
  15. * The SizeRequirements class supports two types of layout:
  16. *
  17. * <blockquote>
  18. * <dl>
  19. * <dt> tiled
  20. * <dd> The components are placed end-to-end,
  21. * starting at coordinate 0
  22. * (the leftmost or topmost position).
  23. *
  24. * <dt> aligned
  25. * <dd> The components are aligned as specified
  26. * by each component's X or Y alignment value.
  27. * </dl>
  28. * </blockquote>
  29. *
  30. * <p>
  31. *
  32. * Each SizeRequirements object contains information
  33. * about either the width (and X alignment)
  34. * or height (and Y alignment)
  35. * of a single component or a group of components:
  36. *
  37. * <blockquote>
  38. * <dl>
  39. * <dt> <code>minimum</code>
  40. * <dd> The smallest reasonable width/height of the component
  41. * or component group, in pixels.
  42. *
  43. * <dt> <code>preferred</code>
  44. * <dd> The natural width/height of the component
  45. * or component group, in pixels.
  46. *
  47. * <dt> <code>maximum</code>
  48. * <dd> The largest reasonable width/height of the component
  49. * or component group, in pixels.
  50. *
  51. * <dt> <code>alignment</code>
  52. * <dd> The X/Y alignment of the component
  53. * or component group.
  54. * </dl>
  55. * </blockquote>
  56. * <p>
  57. * <strong>Warning:</strong>
  58. * Serialized objects of this class will not be compatible with
  59. * future Swing releases. The current serialization support is appropriate
  60. * for short term storage or RMI between applications running the same
  61. * version of Swing. A future release of Swing will provide support for
  62. * long term persistence.
  63. *
  64. * @see Component#getMinimumSize
  65. * @see Component#getPreferredSize
  66. * @see Component#getMaximumSize
  67. * @see Component#getAlignmentX
  68. * @see Component#getAlignmentY
  69. *
  70. * @version 1.25 11/29/01
  71. * @author Timothy Prinzing
  72. */
  73. public class SizeRequirements implements Serializable {
  74. /**
  75. * The minimum size required.
  76. * For a component <code>comp</code>, this should be equal to either
  77. * <code>comp.getMinimumSize().width</code> or
  78. * <code>comp.getMinimumSize().height</code>.
  79. */
  80. public int minimum;
  81. /**
  82. * The preferred (natural) size.
  83. * For a component <code>comp</code>, this should be equal to either
  84. * <code>comp.getPreferredSize().width</code> or
  85. * <code>comp.getPreferredSize().height</code>.
  86. */
  87. public int preferred;
  88. /**
  89. * The maximum size allowed.
  90. * For a component <code>comp</code>, this should be equal to either
  91. * <code>comp.getMaximumSize().width</code> or
  92. * <code>comp.getMaximumSize().height</code>.
  93. */
  94. public int maximum;
  95. /**
  96. * The alignment, specified as a value between 0.0 and 1.0,
  97. * inclusive.
  98. * To specify centering, the alignment should be 0.5.
  99. */
  100. public float alignment;
  101. /**
  102. * Creates a SizeRequirements object with the minimum, preferred,
  103. * and maximum sizes set to zero and an alignment value of 0.5
  104. * (centered).
  105. */
  106. public SizeRequirements() {
  107. minimum = 0;
  108. preferred = 0;
  109. maximum = 0;
  110. alignment = 0.5f;
  111. }
  112. /**
  113. * Creates a SizeRequirements object with the specified minimum, preferred,
  114. * and maximum sizes and the specified alignment.
  115. *
  116. * @param min the minimum size >= 0
  117. * @param pref the preferred size >= 0
  118. * @param max the maximum size >= 0
  119. * @param a the alignment >= 0.0f && <= 1.0f
  120. */
  121. public SizeRequirements(int min, int pref, int max, float a) {
  122. minimum = min;
  123. preferred = pref;
  124. maximum = max;
  125. alignment = a > 1.0f ? 1.0f : a < 0.0f ? 0.0f : a;
  126. }
  127. /**
  128. * Returns a string describing the minimum, preferred, and maximum
  129. * size requirements, along with the alignment.
  130. *
  131. * @return the string
  132. */
  133. public String toString() {
  134. return "[" + minimum + "," + preferred + "," + maximum + "]@" + alignment;
  135. }
  136. /**
  137. * Determines the total space necessary to
  138. * place a set of components end-to-end. The needs
  139. * of each component in the set are represented by an entry in the
  140. * passed-in SizeRequirements array.
  141. * The returned SizeRequirements object has an alignment of 0.5
  142. * (centered). The space requirement is never more than
  143. * Integer.MAX_VALUE.
  144. *
  145. * @param children the space requirements for a set of components.
  146. * The vector may be of zero length, which will result in a
  147. * default SizeRequirements object instance being passed back.
  148. * @return the total space requirements.
  149. */
  150. public static SizeRequirements getTiledSizeRequirements(SizeRequirements[]
  151. children) {
  152. SizeRequirements total = new SizeRequirements();
  153. for (int i = 0; i < children.length; i++) {
  154. SizeRequirements req = children[i];
  155. total.minimum = (int) Math.min((long) total.minimum + (long) req.minimum, Integer.MAX_VALUE);
  156. total.preferred = (int) Math.min((long) total.preferred + (long) req.preferred, Integer.MAX_VALUE);
  157. total.maximum = (int) Math.min((long) total.maximum + (long) req.maximum, Integer.MAX_VALUE);
  158. }
  159. return total;
  160. }
  161. /**
  162. * Determines the total space necessary to
  163. * align a set of components. The needs
  164. * of each component in the set are represented by an entry in the
  165. * passed-in SizeRequirements array. The total space required will
  166. * never be more than Integer.MAX_VALUE.
  167. *
  168. * @param children the set of child requirements. If of zero length,
  169. * the returns result will be a default instance of SizeRequirements.
  170. * @return the total space requirements.
  171. */
  172. public static SizeRequirements getAlignedSizeRequirements(SizeRequirements[]
  173. children) {
  174. SizeRequirements totalAscent = new SizeRequirements();
  175. SizeRequirements totalDescent = new SizeRequirements();
  176. for (int i = 0; i < children.length; i++) {
  177. SizeRequirements req = children[i];
  178. int ascent = (int) (req.alignment * req.minimum);
  179. int descent = req.minimum - ascent;
  180. totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
  181. totalDescent.minimum = Math.max(descent, totalDescent.minimum);
  182. ascent = (int) (req.alignment * req.preferred);
  183. descent = req.preferred - ascent;
  184. totalAscent.preferred = Math.max(ascent, totalAscent.preferred);
  185. totalDescent.preferred = Math.max(descent, totalDescent.preferred);
  186. ascent = (int) (req.alignment * req.maximum);
  187. descent = req.maximum - ascent;
  188. totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
  189. totalDescent.maximum = Math.max(descent, totalDescent.maximum);
  190. }
  191. int min = (int) Math.min((long) totalAscent.minimum + (long) totalDescent.minimum, Integer.MAX_VALUE);
  192. int pref = (int) Math.min((long) totalAscent.preferred + (long) totalDescent.preferred, Integer.MAX_VALUE);
  193. int max = (int) Math.min((long) totalAscent.maximum + (long) totalDescent.maximum, Integer.MAX_VALUE);
  194. float alignment = 0.0f;
  195. if (min > 0) {
  196. alignment = (float) totalAscent.minimum / min;
  197. alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
  198. }
  199. return new SizeRequirements(min, pref, max, alignment);
  200. }
  201. /**
  202. * Creates a bunch of offset/span pairs representing how to
  203. * lay out a set of components end-to-end.
  204. * This method requires that you specify
  205. * the total amount of space to be allocated,
  206. * the size requirements for each component to be placed
  207. * (specified as an array of SizeRequirements), and
  208. * the total size requirement of the set of components.
  209. * You can get the total size requirement
  210. * by invoking the getTiledSizeRequirements method.
  211. *
  212. * @param allocated the total span to be allocated >= 0.
  213. * @param total the total of the children requests. This argument
  214. * is optional and may be null.
  215. * @param children the size requirements for each component.
  216. * @param offsets the offset from 0 for each child where
  217. * the spans were allocated (determines placement of the span).
  218. * @param spans the span allocated for each child to make the
  219. * total target span.
  220. */
  221. public static void calculateTiledPositions(int allocated,
  222. SizeRequirements total,
  223. SizeRequirements[] children,
  224. int[] offsets,
  225. int[] spans) {
  226. // The total argument turns out to be a bad idea since the
  227. // total of all the children can overflow the integer used to
  228. // hold the total. The total must therefore be calculated and
  229. // stored in long variables.
  230. long min = 0;
  231. long pref = 0;
  232. long max = 0;
  233. for (int i = 0; i < children.length; i++) {
  234. min += children[i].minimum;
  235. pref += children[i].preferred;
  236. max += children[i].maximum;
  237. }
  238. if (allocated >= pref) {
  239. expandedTile(allocated, min, pref, max, children, offsets, spans);
  240. } else {
  241. compressedTile(allocated, min, pref, max, children, offsets, spans);
  242. }
  243. }
  244. private static void compressedTile(int allocated, long min, long pref, long max,
  245. SizeRequirements[] request,
  246. int[] offsets, int[] spans) {
  247. // ---- determine what we have to work with ----
  248. float totalPlay = Math.min(pref - allocated, pref - min);
  249. float factor = (pref - min == 0) ? 0.0f : totalPlay / (pref - min);
  250. // ---- make the adjustments ----
  251. int totalOffset = 0;
  252. for (int i = 0; i < spans.length; i++) {
  253. offsets[i] = totalOffset;
  254. SizeRequirements req = request[i];
  255. int play = (int)(factor * (req.preferred - req.minimum));
  256. spans[i] = req.preferred - play;
  257. totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
  258. }
  259. }
  260. private static void expandedTile(int allocated, long min, long pref, long max,
  261. SizeRequirements[] request,
  262. int[] offsets, int[] spans) {
  263. // ---- determine what we have to work with ----
  264. float totalPlay = Math.min(allocated - pref, max - pref);
  265. float factor = (max - pref == 0) ? 0.0f : totalPlay / (max - pref);
  266. // ---- make the adjustments ----
  267. int totalOffset = 0;
  268. for (int i = 0; i < spans.length; i++) {
  269. offsets[i] = totalOffset;
  270. SizeRequirements req = request[i];
  271. int play = (int)(factor * (req.maximum - req.preferred));
  272. spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
  273. totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
  274. }
  275. }
  276. /**
  277. * Creates a bunch of offset/span pairs specifying how to
  278. * lay out a set of components with the specified alignments.
  279. * The resulting span allocations will overlap, with each one
  280. * fitting as well as possible into the given total allocation.
  281. * This method requires that you specify
  282. * the total amount of space to be allocated,
  283. * the size requirements for each component to be placed
  284. * (specified as an array of SizeRequirements), and
  285. * the total size requirements of the set of components
  286. * (only the alignment field of which is actually used).
  287. * You can get the total size requirement by invoking
  288. * getAlignedSizeRequirements.
  289. *
  290. * @param allocated the total span to be allocated >= 0.
  291. * @param total the total of the children requests.
  292. * @param children the size requirements for each component.
  293. * @param offsets the offset from 0 for each child where
  294. * the spans were allocated (determines placement of the span).
  295. * @param spans the span allocated for each child to make the
  296. * total target span.
  297. */
  298. public static void calculateAlignedPositions(int allocated,
  299. SizeRequirements total,
  300. SizeRequirements[] children,
  301. int[] offsets,
  302. int[] spans) {
  303. int totalAscent = (int) (allocated * total.alignment);
  304. int totalDescent = allocated - totalAscent;
  305. for (int i = 0; i < children.length; i++) {
  306. SizeRequirements req = children[i];
  307. int maxAscent = (int) (req.maximum * req.alignment);
  308. int maxDescent = req.maximum - maxAscent;
  309. int ascent = Math.min(totalAscent, maxAscent);
  310. int descent = Math.min(totalDescent, maxDescent);
  311. offsets[i] = totalAscent - ascent;
  312. spans[i] = (int) Math.min((long) ascent + (long) descent, Integer.MAX_VALUE);
  313. }
  314. }
  315. // This method was used by the JTable - which now uses a different technique.
  316. /**
  317. * Adjust a specified array of sizes by a given amount.
  318. *
  319. * @param delta an int specifying the size difference
  320. * @param children an array of SizeRequirements objects
  321. * @return an array of ints containing the final size for each item
  322. */
  323. public static int[] adjustSizes(int delta, SizeRequirements[] children) {
  324. return new int[0];
  325. }
  326. }