1 /* SizeRequirements.java --
2 Copyright (C) 2002, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java
.io
.Serializable
;
43 * This class calculates information about the size and position requirements
46 * Two types of layout are supported:
48 * <li>Tiled: the components are placed at position top-left or bottom-right
49 * position within their allocated space</li>
50 * <li>Aligned: the components are placed aligned in their allocated space
51 * according to their alignment value</li>
54 * @author Andrew Selkirk
55 * @author Roman Kennke (roman@kennke.org)
57 public class SizeRequirements
implements Serializable
60 * The serialVersionUID.
62 private static final long serialVersionUID
= 9217749429906736553L;
65 * The minimum reasonable width or height of a component.
70 * The preferred width or height of a component.
75 * The maximum reasonable width or height of a component.
80 * The horizontal or vertical alignment of a component.
82 public float alignment
;
85 * Creates a SizeRequirements object with minimum, preferred and
86 * maximum size set to zero, and an alignment value of 0.5.
88 public SizeRequirements()
94 * Creates a SizeRequirements object with the specified minimum,
95 * preferred, maximum and alignment values.
97 * @param min the minimum reasonable size of the component
98 * @param pref the preferred size of the component
99 * @param max the maximum size of the component
100 * @param align the alignment of the component
102 public SizeRequirements(int min
, int pref
, int max
, float align
)
111 * Returns a String representation of this SizeRequirements object,
112 * containing information about the minimum, preferred, maximum and
115 * @return a String representation of this SizeRequirements object
117 public String
toString()
119 StringBuilder b
= new StringBuilder();
133 * Calculates how much space is nessecary to place a set of components
134 * end-to-end. The size requirements of the components is specified
135 * in <code>children</code>.
137 * @param children the SizeRequirements of each of the components
139 * @return the SizeRequirements that describe how much space is needed
140 * to place the components end-to-end
142 public static SizeRequirements
143 getTiledSizeRequirements(SizeRequirements
[] children
)
148 for (int i
= 0; i
< children
.length
; i
++)
150 minimum
+= children
[i
].minimum
;
151 preferred
+= children
[i
].preferred
;
152 maximum
+= children
[i
].maximum
;
155 if (minimum
> Integer
.MAX_VALUE
)
156 minimum
= Integer
.MAX_VALUE
;
157 if (preferred
> Integer
.MAX_VALUE
)
158 preferred
= Integer
.MAX_VALUE
;
159 if (maximum
> Integer
.MAX_VALUE
)
160 maximum
= Integer
.MAX_VALUE
;
161 SizeRequirements result
= new SizeRequirements((int) minimum
,
169 * Calculates how much space is nessecary to place a set of components
170 * aligned according to their alignment value.
171 * The size requirements of the components is specified in
172 * <code>children</code>.
174 * @param children the SizeRequirements of each of the components
176 * @return the SizeRequirements that describe how much space is needed
177 * to place the components aligned
179 public static SizeRequirements
180 getAlignedSizeRequirements(SizeRequirements
[] children
)
188 for (int i
= 0; i
< children
.length
; i
++)
190 float myMinLeft
= children
[i
].minimum
* children
[i
].alignment
;
191 float myMinRight
= children
[i
].minimum
- myMinLeft
;
192 minLeft
= Math
.max(myMinLeft
, minLeft
);
193 minRight
= Math
.max(myMinRight
, minRight
);
194 float myPrefLeft
= children
[i
].preferred
* children
[i
].alignment
;
195 float myPrefRight
= children
[i
].preferred
- myPrefLeft
;
196 prefLeft
= Math
.max(myPrefLeft
, prefLeft
);
197 prefRight
= Math
.max(myPrefRight
, prefRight
);
198 float myMaxLeft
= children
[i
].maximum
* children
[i
].alignment
;
199 float myMaxRight
= children
[i
].maximum
- myMaxLeft
;
200 maxLeft
= Math
.max(myMaxLeft
, maxLeft
);
201 maxRight
= Math
.max(myMaxRight
, maxRight
);
203 int minSize
= (int) (minLeft
+ minRight
);
204 int prefSize
= (int) (prefLeft
+ prefRight
);
205 int maxSize
= (int) (maxLeft
+ maxRight
);
206 float align
= prefLeft
/ (prefRight
+ prefLeft
);
207 if (Float
.isNaN(align
))
209 return new SizeRequirements(minSize
, prefSize
, maxSize
, align
);
213 * Calculate the offsets and spans of the components, when they should
214 * be placed end-to-end.
216 * You must specify the amount of allocated space in
217 * <code>allocated</code>, the total size requirements of the set of
218 * components in <code>total</code> (this can be calculated using
219 * {@link #getTiledSizeRequirements} and the size requirements of the
220 * components in <code>children</code>.
222 * The calculated offset and span values for each component are then
223 * stored in the arrays <code>offsets</code> and <code>spans</code>.
225 * The components are placed in the forward direction, beginning with
228 * @param allocated the amount of allocated space
229 * @param total the total size requirements of the components
230 * @param children the size requirement of each component
231 * @param offsets will hold the offset values for each component
232 * @param spans will hold the span values for each component
234 public static void calculateTiledPositions(int allocated
,
235 SizeRequirements total
,
236 SizeRequirements
[] children
,
237 int[] offsets
, int[] spans
)
239 calculateTiledPositions(allocated
, total
, children
, offsets
, spans
, true);
243 * Calculate the offsets and spans of the components, when they should
244 * be placed end-to-end.
246 * You must specify the amount of allocated space in
247 * <code>allocated</code>, the total size requirements of the set of
248 * components in <code>total</code> (this can be calculated using
249 * {@link #getTiledSizeRequirements} and the size requirements of the
250 * components in <code>children</code>.
252 * The calculated offset and span values for each component are then
253 * stored in the arrays <code>offsets</code> and <code>spans</code>.
255 * Depending on the value of <code>forward</code> the components are
256 * placed in the forward direction (left-right or top-bottom), where
257 * the offsets begin with 0, or in the reverse direction
258 * (right-left or bottom-top).
260 * @param allocated the amount of allocated space
261 * @param total the total size requirements of the components
262 * @param children the size requirement of each component
263 * @param offsets will hold the offset values for each component
264 * @param spans will hold the span values for each component
265 * @param forward whether the components should be placed in the forward
266 * direction (left-right or top-bottom) or reverse direction
267 * (right-left or bottom-top)
269 public static void calculateTiledPositions(int allocated
,
270 SizeRequirements total
,
271 SizeRequirements
[] children
,
272 int[] offsets
, int[] spans
,
279 for (int i
= 0; i
< children
.length
; i
++)
282 spans
[i
] = children
[i
].preferred
;
284 offset
+= children
[i
].preferred
;
289 int offset
= allocated
;
290 for (int i
= 0; i
< children
.length
; i
++)
292 offset
-= children
[i
].preferred
;
295 spans
[i
] = children
[i
].preferred
;
298 // Adjust spans so that we exactly fill the allocated region. If
299 if (span
> allocated
)
300 adjustSmaller(allocated
, children
, spans
, span
);
301 else if (span
< allocated
)
302 adjustGreater(allocated
, children
, spans
, span
);
308 for (int i
= 0; i
< children
.length
; i
++)
316 int offset
= allocated
;
317 for (int i
= 0; i
< children
.length
; i
++)
325 private static void adjustSmaller(int allocated
, SizeRequirements
[] children
,
326 int[] spans
, int span
)
328 // Sum up (prefSize - minSize) over all children
330 for (int i
= 0; i
< children
.length
; i
++)
331 sumDelta
+= children
[i
].preferred
- children
[i
].minimum
;
333 // If we have sumDelta == 0, then all components have prefSize == maxSize
334 // and we can't do anything about it.
338 // Adjust all sizes according to their preferred and minimum sizes.
339 for (int i
= 0; i
< children
.length
; i
++)
341 double factor
= ((double) (children
[i
].preferred
- children
[i
].minimum
))
342 / ((double) sumDelta
);
343 // In case we have a sumDelta of 0, the factor should also be 0.
344 if (Double
.isNaN(factor
))
346 spans
[i
] -= factor
* (span
- allocated
);
350 private static void adjustGreater(int allocated
, SizeRequirements
[] children
,
351 int[] spans
, int span
)
353 // Sum up (maxSize - prefSize) over all children
355 for (int i
= 0; i
< children
.length
; i
++)
357 sumDelta
+= children
[i
].maximum
- children
[i
].preferred
;
360 // If we have sumDelta == 0, then all components have prefSize == maxSize
361 // and we can't do anything about it.
365 // Adjust all sizes according to their preferred and minimum sizes.
366 for (int i
= 0; i
< children
.length
; i
++)
368 double factor
= ((double) (children
[i
].maximum
- children
[i
].preferred
))
369 / ((double) sumDelta
);
370 spans
[i
] += factor
* (allocated
- span
);
375 * Calculate the offsets and spans of the components, when they should
376 * be placed end-to-end.
378 * You must specify the amount of allocated space in
379 * <code>allocated</code>, the total size requirements of the set of
380 * components in <code>total</code> (this can be calculated using
381 * {@link #getTiledSizeRequirements} and the size requirements of the
382 * components in <code>children</code>.
384 * The calculated offset and span values for each component are then
385 * stored in the arrays <code>offsets</code> and <code>spans</code>.
387 * The components are tiled in the forward direction, beginning with
390 * @param allocated the amount of allocated space
391 * @param total the total size requirements of the components
392 * @param children the size requirement of each component
393 * @param offsets will hold the offset values for each component
394 * @param spans will hold the span values for each component
396 public static void calculateAlignedPositions(int allocated
,
397 SizeRequirements total
,
398 SizeRequirements
[] children
,
399 int[] offsets
, int[] spans
)
401 calculateAlignedPositions(allocated
, total
, children
, offsets
, spans
,
406 * Calculate the offsets and spans of the components, when they should
407 * be placed end-to-end.
409 * You must specify the amount of allocated space in
410 * <code>allocated</code>, the total size requirements of the set of
411 * components in <code>total</code> (this can be calculated using
412 * {@link #getTiledSizeRequirements} and the size requirements of the
413 * components in <code>children</code>.
415 * The calculated offset and span values for each component are then
416 * stored in the arrays <code>offsets</code> and <code>spans</code>.
418 * Depending on the value of <code>forward</code> the components are
419 * placed in the forward direction (left-right or top-bottom), where
420 * the offsets begin with 0, or in the reverse direction
421 * (right-left or bottom-top).
423 * @param allocated the amount of allocated space
424 * @param total the total size requirements of the components
425 * @param children the size requirement of each component
426 * @param spans will hold the span values for each component
427 * @param forward whether the components should be placed in the forward
428 * direction (left-right or top-bottom) or reverse direction
429 * (right-left or bottom-top)
431 public static void calculateAlignedPositions(int allocated
,
432 SizeRequirements total
,
433 SizeRequirements
[] children
,
434 int[] offset
, int[] spans
,
437 // First we compute the position of the baseline.
438 float baseline
= allocated
* total
.alignment
;
440 // Now we can layout the components along the baseline.
441 for (int i
= 0; i
< children
.length
; i
++)
443 float align
= children
[i
].alignment
;
444 // Try to fit the component into the available space.
445 int[] spanAndOffset
= new int[2];
446 if (align
< .5F
|| baseline
== 0)
447 adjustFromRight(children
[i
], baseline
, allocated
, spanAndOffset
);
449 adjustFromLeft(children
[i
], baseline
, allocated
, spanAndOffset
);
450 spans
[i
] = spanAndOffset
[0];
451 offset
[i
] = spanAndOffset
[1];
456 * Adjusts the span and offset of a component for the aligned layout.
461 * @param spanAndOffset
463 private static void adjustFromRight(SizeRequirements reqs
, float baseline
,
464 int allocated
, int[] spanAndOffset
)
466 float right
= allocated
- baseline
;
467 // If the resulting span exceeds the maximum of the component, then adjust
469 float maxRight
= ((float) reqs
.maximum
) * (1.F
- reqs
.alignment
);
470 if (right
/ (1.F
- reqs
.alignment
) > reqs
.maximum
)
472 // If we have not enough space on the left side, then adjust accordingly.
473 if (right
/ (1.F
- reqs
.alignment
) * reqs
.alignment
> allocated
- baseline
)
474 right
= ((float) (allocated
- baseline
))
475 / reqs
.alignment
* (1.F
- reqs
.alignment
);
477 spanAndOffset
[0] = (int) (right
/ (1.F
- reqs
.alignment
));
478 spanAndOffset
[1] = (int) (baseline
- spanAndOffset
[0] * reqs
.alignment
);
482 * Adjusts the span and offset of a component for the aligned layout.
487 * @param spanAndOffset
489 private static void adjustFromLeft(SizeRequirements reqs
, float baseline
,
490 int allocated
, int[] spanAndOffset
)
492 float left
= baseline
;
493 // If the resulting span exceeds the maximum of the component, then adjust
495 float maxLeft
= ((float) reqs
.maximum
) * reqs
.alignment
;
496 if (left
/ reqs
.alignment
> reqs
.maximum
)
498 // If we have not enough space on the right side, then adjust accordingly.
499 if (left
/ reqs
.alignment
* (1.F
- reqs
.alignment
) > allocated
- baseline
)
500 left
= ((float) (allocated
- baseline
))
501 / (1.F
- reqs
.alignment
) * reqs
.alignment
;
503 spanAndOffset
[0] = (int) (left
/ reqs
.alignment
);
504 spanAndOffset
[1] = (int) (baseline
- spanAndOffset
[0] * reqs
.alignment
);
508 * Returns an array of new preferred sizes for the children based on
509 * <code>delta</code>. <code>delta</code> specifies a change in the
510 * allocated space. The sizes of the children will be shortened or
511 * lengthened to accomodate the new allocation.
513 * @param delta the change of the size of the total allocation for
515 * @param children the size requirements of each component
517 * @return the new preferred sizes for each component
519 public static int[] adjustSizes(int delta
, SizeRequirements
[] children
)