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