0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing;
0N/A
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.io.Serializable;
0N/A
0N/A/**
0N/A * For the convenience of layout managers,
0N/A * calculates information about the size and position of components.
0N/A * All size and position calculation methods are class methods
0N/A * that take arrays of SizeRequirements as arguments.
0N/A * The SizeRequirements class supports two types of layout:
0N/A *
0N/A * <blockquote>
0N/A * <dl>
0N/A * <dt> tiled
0N/A * <dd> The components are placed end-to-end,
0N/A * starting either at coordinate 0 (the leftmost or topmost position)
0N/A * or at the coordinate representing the end of the allocated span
0N/A * (the rightmost or bottommost position).
0N/A *
0N/A * <dt> aligned
0N/A * <dd> The components are aligned as specified
0N/A * by each component's X or Y alignment value.
0N/A * </dl>
0N/A * </blockquote>
0N/A *
0N/A * <p>
0N/A *
0N/A * Each SizeRequirements object contains information
0N/A * about either the width (and X alignment)
0N/A * or height (and Y alignment)
0N/A * of a single component or a group of components:
0N/A *
0N/A * <blockquote>
0N/A * <dl>
0N/A * <dt> <code>minimum</code>
0N/A * <dd> The smallest reasonable width/height of the component
0N/A * or component group, in pixels.
0N/A *
0N/A * <dt> <code>preferred</code>
0N/A * <dd> The natural width/height of the component
0N/A * or component group, in pixels.
0N/A *
0N/A * <dt> <code>maximum</code>
0N/A * <dd> The largest reasonable width/height of the component
0N/A * or component group, in pixels.
0N/A *
0N/A * <dt> <code>alignment</code>
0N/A * <dd> The X/Y alignment of the component
0N/A * or component group.
0N/A * </dl>
0N/A * </blockquote>
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @see Component#getMinimumSize
0N/A * @see Component#getPreferredSize
0N/A * @see Component#getMaximumSize
0N/A * @see Component#getAlignmentX
0N/A * @see Component#getAlignmentY
0N/A *
0N/A * @author Timothy Prinzing
0N/A */
0N/Apublic class SizeRequirements implements Serializable {
0N/A
0N/A /**
0N/A * The minimum size required.
0N/A * For a component <code>comp</code>, this should be equal to either
0N/A * <code>comp.getMinimumSize().width</code> or
0N/A * <code>comp.getMinimumSize().height</code>.
0N/A */
0N/A public int minimum;
0N/A
0N/A /**
0N/A * The preferred (natural) size.
0N/A * For a component <code>comp</code>, this should be equal to either
0N/A * <code>comp.getPreferredSize().width</code> or
0N/A * <code>comp.getPreferredSize().height</code>.
0N/A */
0N/A public int preferred;
0N/A
0N/A /**
0N/A * The maximum size allowed.
0N/A * For a component <code>comp</code>, this should be equal to either
0N/A * <code>comp.getMaximumSize().width</code> or
0N/A * <code>comp.getMaximumSize().height</code>.
0N/A */
0N/A public int maximum;
0N/A
0N/A /**
0N/A * The alignment, specified as a value between 0.0 and 1.0,
0N/A * inclusive.
0N/A * To specify centering, the alignment should be 0.5.
0N/A */
0N/A public float alignment;
0N/A
0N/A /**
0N/A * Creates a SizeRequirements object with the minimum, preferred,
0N/A * and maximum sizes set to zero and an alignment value of 0.5
0N/A * (centered).
0N/A */
0N/A public SizeRequirements() {
0N/A minimum = 0;
0N/A preferred = 0;
0N/A maximum = 0;
0N/A alignment = 0.5f;
0N/A }
0N/A
0N/A /**
0N/A * Creates a SizeRequirements object with the specified minimum, preferred,
0N/A * and maximum sizes and the specified alignment.
0N/A *
0N/A * @param min the minimum size >= 0
0N/A * @param pref the preferred size >= 0
0N/A * @param max the maximum size >= 0
0N/A * @param a the alignment >= 0.0f && <= 1.0f
0N/A */
0N/A public SizeRequirements(int min, int pref, int max, float a) {
0N/A minimum = min;
0N/A preferred = pref;
0N/A maximum = max;
0N/A alignment = a > 1.0f ? 1.0f : a < 0.0f ? 0.0f : a;
0N/A }
0N/A
0N/A /**
0N/A * Returns a string describing the minimum, preferred, and maximum
0N/A * size requirements, along with the alignment.
0N/A *
0N/A * @return the string
0N/A */
0N/A public String toString() {
0N/A return "[" + minimum + "," + preferred + "," + maximum + "]@" + alignment;
0N/A }
0N/A
0N/A /**
0N/A * Determines the total space necessary to
0N/A * place a set of components end-to-end. The needs
0N/A * of each component in the set are represented by an entry in the
0N/A * passed-in SizeRequirements array.
0N/A * The returned SizeRequirements object has an alignment of 0.5
0N/A * (centered). The space requirement is never more than
0N/A * Integer.MAX_VALUE.
0N/A *
0N/A * @param children the space requirements for a set of components.
0N/A * The vector may be of zero length, which will result in a
0N/A * default SizeRequirements object instance being passed back.
0N/A * @return the total space requirements.
0N/A */
0N/A public static SizeRequirements getTiledSizeRequirements(SizeRequirements[]
0N/A children) {
0N/A SizeRequirements total = new SizeRequirements();
0N/A for (int i = 0; i < children.length; i++) {
0N/A SizeRequirements req = children[i];
0N/A total.minimum = (int) Math.min((long) total.minimum + (long) req.minimum, Integer.MAX_VALUE);
0N/A total.preferred = (int) Math.min((long) total.preferred + (long) req.preferred, Integer.MAX_VALUE);
0N/A total.maximum = (int) Math.min((long) total.maximum + (long) req.maximum, Integer.MAX_VALUE);
0N/A }
0N/A return total;
0N/A }
0N/A
0N/A /**
0N/A * Determines the total space necessary to
0N/A * align a set of components. The needs
0N/A * of each component in the set are represented by an entry in the
0N/A * passed-in SizeRequirements array. The total space required will
0N/A * never be more than Integer.MAX_VALUE.
0N/A *
0N/A * @param children the set of child requirements. If of zero length,
0N/A * the returns result will be a default instance of SizeRequirements.
0N/A * @return the total space requirements.
0N/A */
0N/A public static SizeRequirements getAlignedSizeRequirements(SizeRequirements[]
0N/A children) {
0N/A SizeRequirements totalAscent = new SizeRequirements();
0N/A SizeRequirements totalDescent = new SizeRequirements();
0N/A for (int i = 0; i < children.length; i++) {
0N/A SizeRequirements req = children[i];
0N/A
0N/A int ascent = (int) (req.alignment * req.minimum);
0N/A int descent = req.minimum - ascent;
0N/A totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
0N/A totalDescent.minimum = Math.max(descent, totalDescent.minimum);
0N/A
0N/A ascent = (int) (req.alignment * req.preferred);
0N/A descent = req.preferred - ascent;
0N/A totalAscent.preferred = Math.max(ascent, totalAscent.preferred);
0N/A totalDescent.preferred = Math.max(descent, totalDescent.preferred);
0N/A
0N/A ascent = (int) (req.alignment * req.maximum);
0N/A descent = req.maximum - ascent;
0N/A totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
0N/A totalDescent.maximum = Math.max(descent, totalDescent.maximum);
0N/A }
0N/A int min = (int) Math.min((long) totalAscent.minimum + (long) totalDescent.minimum, Integer.MAX_VALUE);
0N/A int pref = (int) Math.min((long) totalAscent.preferred + (long) totalDescent.preferred, Integer.MAX_VALUE);
0N/A int max = (int) Math.min((long) totalAscent.maximum + (long) totalDescent.maximum, Integer.MAX_VALUE);
0N/A float alignment = 0.0f;
0N/A if (min > 0) {
0N/A alignment = (float) totalAscent.minimum / min;
0N/A alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
0N/A }
0N/A return new SizeRequirements(min, pref, max, alignment);
0N/A }
0N/A
0N/A /**
0N/A * Creates a set of offset/span pairs representing how to
0N/A * lay out a set of components end-to-end.
0N/A * This method requires that you specify
0N/A * the total amount of space to be allocated,
0N/A * the size requirements for each component to be placed
0N/A * (specified as an array of SizeRequirements), and
0N/A * the total size requirement of the set of components.
0N/A * You can get the total size requirement
0N/A * by invoking the getTiledSizeRequirements method. The components
0N/A * will be tiled in the forward direction with offsets increasing from 0.
0N/A *
0N/A * @param allocated the total span to be allocated >= 0.
0N/A * @param total the total of the children requests. This argument
0N/A * is optional and may be null.
0N/A * @param children the size requirements for each component.
0N/A * @param offsets the offset from 0 for each child where
0N/A * the spans were allocated (determines placement of the span).
0N/A * @param spans the span allocated for each child to make the
0N/A * total target span.
0N/A */
0N/A public static void calculateTiledPositions(int allocated,
0N/A SizeRequirements total,
0N/A SizeRequirements[] children,
0N/A int[] offsets,
0N/A int[] spans) {
0N/A calculateTiledPositions(allocated, total, children, offsets, spans, true);
0N/A }
0N/A
0N/A /**
0N/A * Creates a set of offset/span pairs representing how to
0N/A * lay out a set of components end-to-end.
0N/A * This method requires that you specify
0N/A * the total amount of space to be allocated,
0N/A * the size requirements for each component to be placed
0N/A * (specified as an array of SizeRequirements), and
0N/A * the total size requirement of the set of components.
0N/A * You can get the total size requirement
0N/A * by invoking the getTiledSizeRequirements method.
0N/A *
0N/A * This method also requires a flag indicating whether components
0N/A * should be tiled in the forward direction (offsets increasing
0N/A * from 0) or reverse direction (offsets decreasing from the end
0N/A * of the allocated space). The forward direction represents
0N/A * components tiled from left to right or top to bottom. The
0N/A * reverse direction represents components tiled from right to left
0N/A * or bottom to top.
0N/A *
0N/A * @param allocated the total span to be allocated >= 0.
0N/A * @param total the total of the children requests. This argument
0N/A * is optional and may be null.
0N/A * @param children the size requirements for each component.
0N/A * @param offsets the offset from 0 for each child where
0N/A * the spans were allocated (determines placement of the span).
0N/A * @param spans the span allocated for each child to make the
0N/A * total target span.
0N/A * @param forward tile with offsets increasing from 0 if true
0N/A * and with offsets decreasing from the end of the allocated space
0N/A * if false.
0N/A * @since 1.4
0N/A */
0N/A public static void calculateTiledPositions(int allocated,
0N/A SizeRequirements total,
0N/A SizeRequirements[] children,
0N/A int[] offsets,
0N/A int[] spans,
0N/A boolean forward) {
0N/A // The total argument turns out to be a bad idea since the
0N/A // total of all the children can overflow the integer used to
0N/A // hold the total. The total must therefore be calculated and
0N/A // stored in long variables.
0N/A long min = 0;
0N/A long pref = 0;
0N/A long max = 0;
0N/A for (int i = 0; i < children.length; i++) {
0N/A min += children[i].minimum;
0N/A pref += children[i].preferred;
0N/A max += children[i].maximum;
0N/A }
0N/A if (allocated >= pref) {
0N/A expandedTile(allocated, min, pref, max, children, offsets, spans, forward);
0N/A } else {
0N/A compressedTile(allocated, min, pref, max, children, offsets, spans, forward);
0N/A }
0N/A }
0N/A
0N/A private static void compressedTile(int allocated, long min, long pref, long max,
0N/A SizeRequirements[] request,
0N/A int[] offsets, int[] spans,
0N/A boolean forward) {
0N/A
0N/A // ---- determine what we have to work with ----
0N/A float totalPlay = Math.min(pref - allocated, pref - min);
0N/A float factor = (pref - min == 0) ? 0.0f : totalPlay / (pref - min);
0N/A
0N/A // ---- make the adjustments ----
0N/A int totalOffset;
0N/A if( forward ) {
0N/A // lay out with offsets increasing from 0
0N/A totalOffset = 0;
0N/A for (int i = 0; i < spans.length; i++) {
0N/A offsets[i] = totalOffset;
0N/A SizeRequirements req = request[i];
0N/A float play = factor * (req.preferred - req.minimum);
0N/A spans[i] = (int)(req.preferred - play);
0N/A totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
0N/A }
0N/A } else {
0N/A // lay out with offsets decreasing from the end of the allocation
0N/A totalOffset = allocated;
0N/A for (int i = 0; i < spans.length; i++) {
0N/A SizeRequirements req = request[i];
0N/A float play = factor * (req.preferred - req.minimum);
0N/A spans[i] = (int)(req.preferred - play);
0N/A offsets[i] = totalOffset - spans[i];
0N/A totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private static void expandedTile(int allocated, long min, long pref, long max,
0N/A SizeRequirements[] request,
0N/A int[] offsets, int[] spans,
0N/A boolean forward) {
0N/A
0N/A // ---- determine what we have to work with ----
0N/A float totalPlay = Math.min(allocated - pref, max - pref);
0N/A float factor = (max - pref == 0) ? 0.0f : totalPlay / (max - pref);
0N/A
0N/A // ---- make the adjustments ----
0N/A int totalOffset;
0N/A if( forward ) {
0N/A // lay out with offsets increasing from 0
0N/A totalOffset = 0;
0N/A for (int i = 0; i < spans.length; i++) {
0N/A offsets[i] = totalOffset;
0N/A SizeRequirements req = request[i];
0N/A int play = (int)(factor * (req.maximum - req.preferred));
0N/A spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
0N/A totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
0N/A }
0N/A } else {
0N/A // lay out with offsets decreasing from the end of the allocation
0N/A totalOffset = allocated;
0N/A for (int i = 0; i < spans.length; i++) {
0N/A SizeRequirements req = request[i];
0N/A int play = (int)(factor * (req.maximum - req.preferred));
0N/A spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
0N/A offsets[i] = totalOffset - spans[i];
0N/A totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a bunch of offset/span pairs specifying how to
0N/A * lay out a set of components with the specified alignments.
0N/A * The resulting span allocations will overlap, with each one
0N/A * fitting as well as possible into the given total allocation.
0N/A * This method requires that you specify
0N/A * the total amount of space to be allocated,
0N/A * the size requirements for each component to be placed
0N/A * (specified as an array of SizeRequirements), and
0N/A * the total size requirements of the set of components
0N/A * (only the alignment field of which is actually used).
0N/A * You can get the total size requirement by invoking
0N/A * getAlignedSizeRequirements.
0N/A *
0N/A * Normal alignment will be done with an alignment value of 0.0f
0N/A * representing the left/top edge of a component.
0N/A *
0N/A * @param allocated the total span to be allocated >= 0.
0N/A * @param total the total of the children requests.
0N/A * @param children the size requirements for each component.
0N/A * @param offsets the offset from 0 for each child where
0N/A * the spans were allocated (determines placement of the span).
0N/A * @param spans the span allocated for each child to make the
0N/A * total target span.
0N/A */
0N/A public static void calculateAlignedPositions(int allocated,
0N/A SizeRequirements total,
0N/A SizeRequirements[] children,
0N/A int[] offsets,
0N/A int[] spans) {
0N/A calculateAlignedPositions( allocated, total, children, offsets, spans, true );
0N/A }
0N/A
0N/A /**
0N/A * Creates a set of offset/span pairs specifying how to
0N/A * lay out a set of components with the specified alignments.
0N/A * The resulting span allocations will overlap, with each one
0N/A * fitting as well as possible into the given total allocation.
0N/A * This method requires that you specify
0N/A * the total amount of space to be allocated,
0N/A * the size requirements for each component to be placed
0N/A * (specified as an array of SizeRequirements), and
0N/A * the total size requirements of the set of components
0N/A * (only the alignment field of which is actually used)
0N/A * You can get the total size requirement by invoking
0N/A * getAlignedSizeRequirements.
0N/A *
0N/A * This method also requires a flag indicating whether normal or
0N/A * reverse alignment should be performed. With normal alignment
0N/A * the value 0.0f represents the left/top edge of the component
0N/A * to be aligned. With reverse alignment, 0.0f represents the
0N/A * right/bottom edge.
0N/A *
0N/A * @param allocated the total span to be allocated >= 0.
0N/A * @param total the total of the children requests.
0N/A * @param children the size requirements for each component.
0N/A * @param offsets the offset from 0 for each child where
0N/A * the spans were allocated (determines placement of the span).
0N/A * @param spans the span allocated for each child to make the
0N/A * total target span.
0N/A * @param normal when true, the alignment value 0.0f means
0N/A * left/top; when false, it means right/bottom.
0N/A * @since 1.4
0N/A */
0N/A public static void calculateAlignedPositions(int allocated,
0N/A SizeRequirements total,
0N/A SizeRequirements[] children,
0N/A int[] offsets,
0N/A int[] spans,
0N/A boolean normal) {
0N/A float totalAlignment = normal ? total.alignment : 1.0f - total.alignment;
0N/A int totalAscent = (int)(allocated * totalAlignment);
0N/A int totalDescent = allocated - totalAscent;
0N/A for (int i = 0; i < children.length; i++) {
0N/A SizeRequirements req = children[i];
0N/A float alignment = normal ? req.alignment : 1.0f - req.alignment;
0N/A int maxAscent = (int)(req.maximum * alignment);
0N/A int maxDescent = req.maximum - maxAscent;
0N/A int ascent = Math.min(totalAscent, maxAscent);
0N/A int descent = Math.min(totalDescent, maxDescent);
0N/A
0N/A offsets[i] = totalAscent - ascent;
0N/A spans[i] = (int) Math.min((long) ascent + (long) descent, Integer.MAX_VALUE);
0N/A }
0N/A }
0N/A
0N/A // This method was used by the JTable - which now uses a different technique.
0N/A /**
0N/A * Adjust a specified array of sizes by a given amount.
0N/A *
0N/A * @param delta an int specifying the size difference
0N/A * @param children an array of SizeRequirements objects
0N/A * @return an array of ints containing the final size for each item
0N/A */
0N/A public static int[] adjustSizes(int delta, SizeRequirements[] children) {
0N/A return new int[0];
0N/A }
0N/A}