summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/SizeRequirements.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/SizeRequirements.java')
-rw-r--r--libjava/classpath/javax/swing/SizeRequirements.java523
1 files changed, 523 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/SizeRequirements.java b/libjava/classpath/javax/swing/SizeRequirements.java
new file mode 100644
index 000000000..1ee0e285c
--- /dev/null
+++ b/libjava/classpath/javax/swing/SizeRequirements.java
@@ -0,0 +1,523 @@
+/* SizeRequirements.java --
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing;
+
+import java.io.Serializable;
+
+/**
+ * This class calculates information about the size and position requirements
+ * of components.
+ *
+ * Two types of layout are supported:
+ * <ul>
+ * <li>Tiled: the components are placed at position top-left or bottom-right
+ * position within their allocated space</li>
+ * <li>Aligned: the components are placed aligned in their allocated space
+ * according to their alignment value</li>
+ * </ul>
+ *
+ * @author Andrew Selkirk
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public class SizeRequirements implements Serializable
+{
+ /**
+ * The serialVersionUID.
+ */
+ private static final long serialVersionUID = 9217749429906736553L;
+
+ /**
+ * The minimum reasonable width or height of a component.
+ */
+ public int minimum;
+
+ /**
+ * The preferred width or height of a component.
+ */
+ public int preferred;
+
+ /**
+ * The maximum reasonable width or height of a component.
+ */
+ public int maximum;
+
+ /**
+ * The horizontal or vertical alignment of a component.
+ */
+ public float alignment;
+
+ /**
+ * Creates a SizeRequirements object with minimum, preferred and
+ * maximum size set to zero, and an alignment value of 0.5.
+ */
+ public SizeRequirements()
+ {
+ this (0, 0, 0, 0.5F);
+ }
+
+ /**
+ * Creates a SizeRequirements object with the specified minimum,
+ * preferred, maximum and alignment values.
+ *
+ * @param min the minimum reasonable size of the component
+ * @param pref the preferred size of the component
+ * @param max the maximum size of the component
+ * @param align the alignment of the component
+ */
+ public SizeRequirements(int min, int pref, int max, float align)
+ {
+ minimum = min;
+ preferred = pref;
+ maximum = max;
+ alignment = align;
+ }
+
+ /**
+ * Returns a String representation of this SizeRequirements object,
+ * containing information about the minimum, preferred, maximum and
+ * alignment value.
+ *
+ * @return a String representation of this SizeRequirements object
+ */
+ public String toString()
+ {
+ StringBuilder b = new StringBuilder();
+ b.append("<[");
+ b.append(minimum);
+ b.append(',');
+ b.append(preferred);
+ b.append(',');
+ b.append(maximum);
+ b.append("]@");
+ b.append(alignment);
+ b.append('>');
+ return b.toString();
+ }
+
+ /**
+ * Calculates how much space is nessecary to place a set of components
+ * end-to-end. The size requirements of the components is specified
+ * in <code>children</code>.
+ *
+ * @param children the SizeRequirements of each of the components
+ *
+ * @return the SizeRequirements that describe how much space is needed
+ * to place the components end-to-end
+ */
+ public static SizeRequirements
+ getTiledSizeRequirements(SizeRequirements[] children)
+ {
+ long minimum = 0;
+ long preferred = 0;
+ long maximum = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ minimum += children[i].minimum;
+ preferred += children[i].preferred;
+ maximum += children[i].maximum;
+ }
+ // Overflow check.
+ if (minimum > Integer.MAX_VALUE)
+ minimum = Integer.MAX_VALUE;
+ if (preferred > Integer.MAX_VALUE)
+ preferred = Integer.MAX_VALUE;
+ if (maximum > Integer.MAX_VALUE)
+ maximum = Integer.MAX_VALUE;
+ SizeRequirements result = new SizeRequirements((int) minimum,
+ (int) preferred,
+ (int) maximum,
+ 0.5F);
+ return result;
+ }
+
+ /**
+ * Calculates how much space is nessecary to place a set of components
+ * aligned according to their alignment value.
+ * The size requirements of the components is specified in
+ * <code>children</code>.
+ *
+ * @param children the SizeRequirements of each of the components
+ *
+ * @return the SizeRequirements that describe how much space is needed
+ * to place the components aligned
+ */
+ public static SizeRequirements
+ getAlignedSizeRequirements(SizeRequirements[] children)
+ {
+ float minLeft = 0;
+ float minRight = 0;
+ float prefLeft = 0;
+ float prefRight = 0;
+ float maxLeft = 0;
+ float maxRight = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ float myMinLeft = children[i].minimum * children[i].alignment;
+ float myMinRight = children[i].minimum - myMinLeft;
+ minLeft = Math.max(myMinLeft, minLeft);
+ minRight = Math.max(myMinRight, minRight);
+ float myPrefLeft = children[i].preferred * children[i].alignment;
+ float myPrefRight = children[i].preferred - myPrefLeft;
+ prefLeft = Math.max(myPrefLeft, prefLeft);
+ prefRight = Math.max(myPrefRight, prefRight);
+ float myMaxLeft = children[i].maximum * children[i].alignment;
+ float myMaxRight = children[i].maximum - myMaxLeft;
+ maxLeft = Math.max(myMaxLeft, maxLeft);
+ maxRight = Math.max(myMaxRight, maxRight);
+ }
+ int minSize = (int) (minLeft + minRight);
+ int prefSize = (int) (prefLeft + prefRight);
+ int maxSize = (int) (maxLeft + maxRight);
+ float align = prefLeft / (prefRight + prefLeft);
+ if (Float.isNaN(align))
+ align = 0;
+ return new SizeRequirements(minSize, prefSize, maxSize, align);
+ }
+
+ /**
+ * Calculate the offsets and spans of the components, when they should
+ * be placed end-to-end.
+ *
+ * You must specify the amount of allocated space in
+ * <code>allocated</code>, the total size requirements of the set of
+ * components in <code>total</code> (this can be calculated using
+ * {@link #getTiledSizeRequirements} and the size requirements of the
+ * components in <code>children</code>.
+ *
+ * The calculated offset and span values for each component are then
+ * stored in the arrays <code>offsets</code> and <code>spans</code>.
+ *
+ * The components are placed in the forward direction, beginning with
+ * an offset of 0.
+ *
+ * @param allocated the amount of allocated space
+ * @param total the total size requirements of the components
+ * @param children the size requirement of each component
+ * @param offsets will hold the offset values for each component
+ * @param spans will hold the span values for each component
+ */
+ public static void calculateTiledPositions(int allocated,
+ SizeRequirements total,
+ SizeRequirements[] children,
+ int[] offsets, int[] spans)
+ {
+ calculateTiledPositions(allocated, total, children, offsets, spans, true);
+ }
+
+ /**
+ * Calculate the offsets and spans of the components, when they should
+ * be placed end-to-end.
+ *
+ * You must specify the amount of allocated space in
+ * <code>allocated</code>, the total size requirements of the set of
+ * components in <code>total</code> (this can be calculated using
+ * {@link #getTiledSizeRequirements} and the size requirements of the
+ * components in <code>children</code>.
+ *
+ * The calculated offset and span values for each component are then
+ * stored in the arrays <code>offsets</code> and <code>spans</code>.
+ *
+ * Depending on the value of <code>forward</code> the components are
+ * placed in the forward direction (left-right or top-bottom), where
+ * the offsets begin with 0, or in the reverse direction
+ * (right-left or bottom-top).
+ *
+ * @param allocated the amount of allocated space
+ * @param total the total size requirements of the components
+ * @param children the size requirement of each component
+ * @param offsets will hold the offset values for each component
+ * @param spans will hold the span values for each component
+ * @param forward whether the components should be placed in the forward
+ * direction (left-right or top-bottom) or reverse direction
+ * (right-left or bottom-top)
+ */
+ public static void calculateTiledPositions(int allocated,
+ SizeRequirements total,
+ SizeRequirements[] children,
+ int[] offsets, int[] spans,
+ boolean forward)
+ {
+ int span = 0;
+ if (forward)
+ {
+ int offset = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ offsets[i] = offset;
+ spans[i] = children[i].preferred;
+ span += spans[i];
+ offset += children[i].preferred;
+ }
+ }
+ else
+ {
+ int offset = allocated;
+ for (int i = 0; i < children.length; i++)
+ {
+ offset -= children[i].preferred;
+ offsets[i] = offset;
+ span += spans[i];
+ spans[i] = children[i].preferred;
+ }
+ }
+ // Adjust spans so that we exactly fill the allocated region. If
+ if (span > allocated)
+ adjustSmaller(allocated, children, spans, span);
+ else if (span < allocated)
+ adjustGreater(allocated, children, spans, span);
+
+ // Adjust offsets.
+ if (forward)
+ {
+ int offset = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ offsets[i] = offset;
+ offset += spans[i];
+ }
+ }
+ else
+ {
+ int offset = allocated;
+ for (int i = 0; i < children.length; i++)
+ {
+ offset -= spans[i];
+ offsets[i] = offset;
+ }
+ }
+ }
+
+ private static void adjustSmaller(int allocated, SizeRequirements[] children,
+ int[] spans, int span)
+ {
+ // Sum up (prefSize - minSize) over all children
+ int sumDelta = 0;
+ for (int i = 0; i < children.length; i++)
+ sumDelta += children[i].preferred - children[i].minimum;
+
+ // If we have sumDelta == 0, then all components have prefSize == maxSize
+ // and we can't do anything about it.
+ if (sumDelta == 0)
+ return;
+
+ // Adjust all sizes according to their preferred and minimum sizes.
+ for (int i = 0; i < children.length; i++)
+ {
+ double factor = ((double) (children[i].preferred - children[i].minimum))
+ / ((double) sumDelta);
+ // In case we have a sumDelta of 0, the factor should also be 0.
+ if (Double.isNaN(factor))
+ factor = 0;
+ spans[i] -= factor * (span - allocated);
+ }
+ }
+
+ private static void adjustGreater(int allocated, SizeRequirements[] children,
+ int[] spans, int span)
+ {
+ // Sum up (maxSize - prefSize) over all children
+ long sumDelta = 0;
+ for (int i = 0; i < children.length; i++)
+ {
+ sumDelta += children[i].maximum - children[i].preferred;
+ }
+
+ // If we have sumDelta == 0, then all components have prefSize == maxSize
+ // and we can't do anything about it.
+ if (sumDelta == 0)
+ return;
+
+ // Adjust all sizes according to their preferred and minimum sizes.
+ for (int i = 0; i < children.length; i++)
+ {
+ double factor = ((double) (children[i].maximum - children[i].preferred))
+ / ((double) sumDelta);
+ spans[i] += factor * (allocated - span);
+ }
+ }
+
+ /**
+ * Calculate the offsets and spans of the components, when they should
+ * be placed end-to-end.
+ *
+ * You must specify the amount of allocated space in
+ * <code>allocated</code>, the total size requirements of the set of
+ * components in <code>total</code> (this can be calculated using
+ * {@link #getTiledSizeRequirements} and the size requirements of the
+ * components in <code>children</code>.
+ *
+ * The calculated offset and span values for each component are then
+ * stored in the arrays <code>offsets</code> and <code>spans</code>.
+ *
+ * The components are tiled in the forward direction, beginning with
+ * an offset of 0.
+ *
+ * @param allocated the amount of allocated space
+ * @param total the total size requirements of the components
+ * @param children the size requirement of each component
+ * @param offsets will hold the offset values for each component
+ * @param spans will hold the span values for each component
+ */
+ public static void calculateAlignedPositions(int allocated,
+ SizeRequirements total,
+ SizeRequirements[] children,
+ int[] offsets, int[] spans)
+ {
+ calculateAlignedPositions(allocated, total, children, offsets, spans,
+ true);
+ }
+
+ /**
+ * Calculate the offsets and spans of the components, when they should
+ * be placed end-to-end.
+ *
+ * You must specify the amount of allocated space in
+ * <code>allocated</code>, the total size requirements of the set of
+ * components in <code>total</code> (this can be calculated using
+ * {@link #getTiledSizeRequirements} and the size requirements of the
+ * components in <code>children</code>.
+ *
+ * The calculated offset and span values for each component are then
+ * stored in the arrays <code>offsets</code> and <code>spans</code>.
+ *
+ * Depending on the value of <code>forward</code> the components are
+ * placed in the forward direction (left-right or top-bottom), where
+ * the offsets begin with 0, or in the reverse direction
+ * (right-left or bottom-top).
+ *
+ * @param allocated the amount of allocated space
+ * @param total the total size requirements of the components
+ * @param children the size requirement of each component
+ * @param spans will hold the span values for each component
+ * @param forward whether the components should be placed in the forward
+ * direction (left-right or top-bottom) or reverse direction
+ * (right-left or bottom-top)
+ */
+ public static void calculateAlignedPositions(int allocated,
+ SizeRequirements total,
+ SizeRequirements[] children,
+ int[] offset, int[] spans,
+ boolean forward)
+ {
+ // First we compute the position of the baseline.
+ float baseline = allocated * total.alignment;
+
+ // Now we can layout the components along the baseline.
+ for (int i = 0; i < children.length; i++)
+ {
+ float align = children[i].alignment;
+ // Try to fit the component into the available space.
+ int[] spanAndOffset = new int[2];
+ if (align < .5F || baseline == 0)
+ adjustFromRight(children[i], baseline, allocated, spanAndOffset);
+ else
+ adjustFromLeft(children[i], baseline, allocated, spanAndOffset);
+ spans[i] = spanAndOffset[0];
+ offset[i] = spanAndOffset[1];
+ }
+ }
+
+ /**
+ * Adjusts the span and offset of a component for the aligned layout.
+ *
+ * @param reqs
+ * @param baseline
+ * @param allocated
+ * @param spanAndOffset
+ */
+ private static void adjustFromRight(SizeRequirements reqs, float baseline,
+ int allocated, int[] spanAndOffset)
+ {
+ float right = allocated - baseline;
+ // If the resulting span exceeds the maximum of the component, then adjust
+ // accordingly.
+ float maxRight = ((float) reqs.maximum) * (1.F - reqs.alignment);
+ if (right / (1.F - reqs.alignment) > reqs.maximum)
+ right = maxRight;
+ // If we have not enough space on the left side, then adjust accordingly.
+ if (right / (1.F - reqs.alignment) * reqs.alignment > allocated - baseline)
+ right = ((float) (allocated - baseline))
+ / reqs.alignment * (1.F - reqs.alignment);
+
+ spanAndOffset[0] = (int) (right / (1.F - reqs.alignment));
+ spanAndOffset[1] = (int) (baseline - spanAndOffset[0] * reqs.alignment);
+ }
+
+ /**
+ * Adjusts the span and offset of a component for the aligned layout.
+ *
+ * @param reqs
+ * @param baseline
+ * @param allocated
+ * @param spanAndOffset
+ */
+ private static void adjustFromLeft(SizeRequirements reqs, float baseline,
+ int allocated, int[] spanAndOffset)
+ {
+ float left = baseline;
+ // If the resulting span exceeds the maximum of the component, then adjust
+ // accordingly.
+ float maxLeft = ((float) reqs.maximum) * reqs.alignment;
+ if (left / reqs.alignment > reqs.maximum)
+ left = maxLeft;
+ // If we have not enough space on the right side, then adjust accordingly.
+ if (left / reqs.alignment * (1.F - reqs.alignment) > allocated - baseline)
+ left = ((float) (allocated - baseline))
+ / (1.F - reqs.alignment) * reqs.alignment;
+
+ spanAndOffset[0] = (int) (left / reqs.alignment);
+ spanAndOffset[1] = (int) (baseline - spanAndOffset[0] * reqs.alignment);
+ }
+
+ /**
+ * Returns an array of new preferred sizes for the children based on
+ * <code>delta</code>. <code>delta</code> specifies a change in the
+ * allocated space. The sizes of the children will be shortened or
+ * lengthened to accomodate the new allocation.
+ *
+ * @param delta the change of the size of the total allocation for
+ * the components
+ * @param children the size requirements of each component
+ *
+ * @return the new preferred sizes for each component
+ */
+ public static int[] adjustSizes(int delta, SizeRequirements[] children)
+ {
+ return null; // TODO
+ }
+}