Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package javax.swing;
   26   
   27   
   28   import java.awt;
   29   import java.io.Serializable;
   30   
   31   /**
   32    * For the convenience of layout managers,
   33    * calculates information about the size and position of components.
   34    * All size and position calculation methods are class methods
   35    * that take arrays of SizeRequirements as arguments.
   36    * The SizeRequirements class supports two types of layout:
   37    *
   38    * <blockquote>
   39    * <dl>
   40    * <dt> tiled
   41    * <dd> The components are placed end-to-end,
   42    *      starting either at coordinate 0 (the leftmost or topmost position)
   43    *      or at the coordinate representing the end of the allocated span
   44    *      (the rightmost or bottommost position).
   45    *
   46    * <dt> aligned
   47    * <dd> The components are aligned as specified
   48    *      by each component's X or Y alignment value.
   49    * </dl>
   50    * </blockquote>
   51    *
   52    * <p>
   53    *
   54    * Each SizeRequirements object contains information
   55    * about either the width (and X alignment)
   56    * or height (and Y alignment)
   57    * of a single component or a group of components:
   58    *
   59    * <blockquote>
   60    * <dl>
   61    * <dt> <code>minimum</code>
   62    * <dd> The smallest reasonable width/height of the component
   63    *      or component group, in pixels.
   64    *
   65    * <dt> <code>preferred</code>
   66    * <dd> The natural width/height of the component
   67    *      or component group, in pixels.
   68    *
   69    * <dt> <code>maximum</code>
   70    * <dd> The largest reasonable width/height of the component
   71    *      or component group, in pixels.
   72    *
   73    * <dt> <code>alignment</code>
   74    * <dd> The X/Y alignment of the component
   75    *      or component group.
   76    * </dl>
   77    * </blockquote>
   78    * <p>
   79    * <strong>Warning:</strong>
   80    * Serialized objects of this class will not be compatible with
   81    * future Swing releases. The current serialization support is
   82    * appropriate for short term storage or RMI between applications running
   83    * the same version of Swing.  As of 1.4, support for long term storage
   84    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   85    * has been added to the <code>java.beans</code> package.
   86    * Please see {@link java.beans.XMLEncoder}.
   87    *
   88    * @see Component#getMinimumSize
   89    * @see Component#getPreferredSize
   90    * @see Component#getMaximumSize
   91    * @see Component#getAlignmentX
   92    * @see Component#getAlignmentY
   93    *
   94    * @author Timothy Prinzing
   95    */
   96   public class SizeRequirements implements Serializable {
   97   
   98       /**
   99        * The minimum size required.
  100        * For a component <code>comp</code>, this should be equal to either
  101        * <code>comp.getMinimumSize().width</code> or
  102        * <code>comp.getMinimumSize().height</code>.
  103        */
  104       public int minimum;
  105   
  106       /**
  107        * The preferred (natural) size.
  108        * For a component <code>comp</code>, this should be equal to either
  109        * <code>comp.getPreferredSize().width</code> or
  110        * <code>comp.getPreferredSize().height</code>.
  111        */
  112       public int preferred;
  113   
  114       /**
  115        * The maximum size allowed.
  116        * For a component <code>comp</code>, this should be equal to either
  117        * <code>comp.getMaximumSize().width</code> or
  118        * <code>comp.getMaximumSize().height</code>.
  119        */
  120       public int maximum;
  121   
  122       /**
  123        * The alignment, specified as a value between 0.0 and 1.0,
  124        * inclusive.
  125        * To specify centering, the alignment should be 0.5.
  126        */
  127       public float alignment;
  128   
  129       /**
  130        * Creates a SizeRequirements object with the minimum, preferred,
  131        * and maximum sizes set to zero and an alignment value of 0.5
  132        * (centered).
  133        */
  134       public SizeRequirements() {
  135           minimum = 0;
  136           preferred = 0;
  137           maximum = 0;
  138           alignment = 0.5f;
  139       }
  140   
  141       /**
  142        * Creates a SizeRequirements object with the specified minimum, preferred,
  143        * and maximum sizes and the specified alignment.
  144        *
  145        * @param min the minimum size >= 0
  146        * @param pref the preferred size >= 0
  147        * @param max the maximum size >= 0
  148        * @param a the alignment >= 0.0f && <= 1.0f
  149        */
  150       public SizeRequirements(int min, int pref, int max, float a) {
  151           minimum = min;
  152           preferred = pref;
  153           maximum = max;
  154           alignment = a > 1.0f ? 1.0f : a < 0.0f ? 0.0f : a;
  155       }
  156   
  157       /**
  158        * Returns a string describing the minimum, preferred, and maximum
  159        * size requirements, along with the alignment.
  160        *
  161        * @return the string
  162        */
  163       public String toString() {
  164           return "[" + minimum + "," + preferred + "," + maximum + "]@" + alignment;
  165       }
  166   
  167       /**
  168        * Determines the total space necessary to
  169        * place a set of components end-to-end.  The needs
  170        * of each component in the set are represented by an entry in the
  171        * passed-in SizeRequirements array.
  172        * The returned SizeRequirements object has an alignment of 0.5
  173        * (centered).  The space requirement is never more than
  174        * Integer.MAX_VALUE.
  175        *
  176        * @param children  the space requirements for a set of components.
  177        *   The vector may be of zero length, which will result in a
  178        *   default SizeRequirements object instance being passed back.
  179        * @return  the total space requirements.
  180        */
  181       public static SizeRequirements getTiledSizeRequirements(SizeRequirements[]
  182                                                               children) {
  183           SizeRequirements total = new SizeRequirements();
  184           for (int i = 0; i < children.length; i++) {
  185               SizeRequirements req = children[i];
  186               total.minimum = (int) Math.min((long) total.minimum + (long) req.minimum, Integer.MAX_VALUE);
  187               total.preferred = (int) Math.min((long) total.preferred + (long) req.preferred, Integer.MAX_VALUE);
  188               total.maximum = (int) Math.min((long) total.maximum + (long) req.maximum, Integer.MAX_VALUE);
  189           }
  190           return total;
  191       }
  192   
  193       /**
  194        * Determines the total space necessary to
  195        * align a set of components.  The needs
  196        * of each component in the set are represented by an entry in the
  197        * passed-in SizeRequirements array.  The total space required will
  198        * never be more than Integer.MAX_VALUE.
  199        *
  200        * @param children  the set of child requirements.  If of zero length,
  201        *  the returns result will be a default instance of SizeRequirements.
  202        * @return  the total space requirements.
  203        */
  204       public static SizeRequirements getAlignedSizeRequirements(SizeRequirements[]
  205                                                                 children) {
  206           SizeRequirements totalAscent = new SizeRequirements();
  207           SizeRequirements totalDescent = new SizeRequirements();
  208           for (int i = 0; i < children.length; i++) {
  209               SizeRequirements req = children[i];
  210   
  211               int ascent = (int) (req.alignment * req.minimum);
  212               int descent = req.minimum - ascent;
  213               totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
  214               totalDescent.minimum = Math.max(descent, totalDescent.minimum);
  215   
  216               ascent = (int) (req.alignment * req.preferred);
  217               descent = req.preferred - ascent;
  218               totalAscent.preferred = Math.max(ascent, totalAscent.preferred);
  219               totalDescent.preferred = Math.max(descent, totalDescent.preferred);
  220   
  221               ascent = (int) (req.alignment * req.maximum);
  222               descent = req.maximum - ascent;
  223               totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
  224               totalDescent.maximum = Math.max(descent, totalDescent.maximum);
  225           }
  226           int min = (int) Math.min((long) totalAscent.minimum + (long) totalDescent.minimum, Integer.MAX_VALUE);
  227           int pref = (int) Math.min((long) totalAscent.preferred + (long) totalDescent.preferred, Integer.MAX_VALUE);
  228           int max = (int) Math.min((long) totalAscent.maximum + (long) totalDescent.maximum, Integer.MAX_VALUE);
  229           float alignment = 0.0f;
  230           if (min > 0) {
  231               alignment = (float) totalAscent.minimum / min;
  232               alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
  233           }
  234           return new SizeRequirements(min, pref, max, alignment);
  235       }
  236   
  237       /**
  238        * Creates a set of offset/span pairs representing how to
  239        * lay out a set of components end-to-end.
  240        * This method requires that you specify
  241        * the total amount of space to be allocated,
  242        * the size requirements for each component to be placed
  243        * (specified as an array of SizeRequirements), and
  244        * the total size requirement of the set of components.
  245        * You can get the total size requirement
  246        * by invoking the getTiledSizeRequirements method.  The components
  247        * will be tiled in the forward direction with offsets increasing from 0.
  248        *
  249        * @param allocated the total span to be allocated >= 0.
  250        * @param total     the total of the children requests.  This argument
  251        *  is optional and may be null.
  252        * @param children  the size requirements for each component.
  253        * @param offsets   the offset from 0 for each child where
  254        *   the spans were allocated (determines placement of the span).
  255        * @param spans     the span allocated for each child to make the
  256        *   total target span.
  257        */
  258       public static void calculateTiledPositions(int allocated,
  259                                                  SizeRequirements total,
  260                                                  SizeRequirements[] children,
  261                                                  int[] offsets,
  262                                                  int[] spans) {
  263           calculateTiledPositions(allocated, total, children, offsets, spans, true);
  264       }
  265   
  266       /**
  267        * Creates a set of offset/span pairs representing how to
  268        * lay out a set of components end-to-end.
  269        * This method requires that you specify
  270        * the total amount of space to be allocated,
  271        * the size requirements for each component to be placed
  272        * (specified as an array of SizeRequirements), and
  273        * the total size requirement of the set of components.
  274        * You can get the total size requirement
  275        * by invoking the getTiledSizeRequirements method.
  276        *
  277        * This method also requires a flag indicating whether components
  278        * should be tiled in the forward direction (offsets increasing
  279        * from 0) or reverse direction (offsets decreasing from the end
  280        * of the allocated space).  The forward direction represents
  281        * components tiled from left to right or top to bottom.  The
  282        * reverse direction represents components tiled from right to left
  283        * or bottom to top.
  284        *
  285        * @param allocated the total span to be allocated >= 0.
  286        * @param total     the total of the children requests.  This argument
  287        *  is optional and may be null.
  288        * @param children  the size requirements for each component.
  289        * @param offsets   the offset from 0 for each child where
  290        *   the spans were allocated (determines placement of the span).
  291        * @param spans     the span allocated for each child to make the
  292        *   total target span.
  293        * @param forward   tile with offsets increasing from 0 if true
  294        *   and with offsets decreasing from the end of the allocated space
  295        *   if false.
  296        * @since 1.4
  297        */
  298       public static void calculateTiledPositions(int allocated,
  299                                                  SizeRequirements total,
  300                                                  SizeRequirements[] children,
  301                                                  int[] offsets,
  302                                                  int[] spans,
  303                                                  boolean forward) {
  304           // The total argument turns out to be a bad idea since the
  305           // total of all the children can overflow the integer used to
  306           // hold the total.  The total must therefore be calculated and
  307           // stored in long variables.
  308           long min = 0;
  309           long pref = 0;
  310           long max = 0;
  311           for (int i = 0; i < children.length; i++) {
  312               min += children[i].minimum;
  313               pref += children[i].preferred;
  314               max += children[i].maximum;
  315           }
  316           if (allocated >= pref) {
  317               expandedTile(allocated, min, pref, max, children, offsets, spans, forward);
  318           } else {
  319               compressedTile(allocated, min, pref, max, children, offsets, spans, forward);
  320           }
  321       }
  322   
  323       private static void compressedTile(int allocated, long min, long pref, long max,
  324                                          SizeRequirements[] request,
  325                                          int[] offsets, int[] spans,
  326                                          boolean forward) {
  327   
  328           // ---- determine what we have to work with ----
  329           float totalPlay = Math.min(pref - allocated, pref - min);
  330           float factor = (pref - min == 0) ? 0.0f : totalPlay / (pref - min);
  331   
  332           // ---- make the adjustments ----
  333           int totalOffset;
  334           if( forward ) {
  335               // lay out with offsets increasing from 0
  336               totalOffset = 0;
  337               for (int i = 0; i < spans.length; i++) {
  338                   offsets[i] = totalOffset;
  339                   SizeRequirements req = request[i];
  340                   float play = factor * (req.preferred - req.minimum);
  341                   spans[i] = (int)(req.preferred - play);
  342                   totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
  343               }
  344           } else {
  345               // lay out with offsets decreasing from the end of the allocation
  346               totalOffset = allocated;
  347               for (int i = 0; i < spans.length; i++) {
  348                   SizeRequirements req = request[i];
  349                   float play = factor * (req.preferred - req.minimum);
  350                   spans[i] = (int)(req.preferred - play);
  351                   offsets[i] = totalOffset - spans[i];
  352                   totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
  353               }
  354           }
  355       }
  356   
  357       private static void expandedTile(int allocated, long min, long pref, long max,
  358                                        SizeRequirements[] request,
  359                                        int[] offsets, int[] spans,
  360                                        boolean forward) {
  361   
  362           // ---- determine what we have to work with ----
  363           float totalPlay = Math.min(allocated - pref, max - pref);
  364           float factor = (max - pref == 0) ? 0.0f : totalPlay / (max - pref);
  365   
  366           // ---- make the adjustments ----
  367           int totalOffset;
  368           if( forward ) {
  369               // lay out with offsets increasing from 0
  370               totalOffset = 0;
  371               for (int i = 0; i < spans.length; i++) {
  372                   offsets[i] = totalOffset;
  373                   SizeRequirements req = request[i];
  374                   int play = (int)(factor * (req.maximum - req.preferred));
  375                   spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
  376                   totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
  377               }
  378           } else {
  379               // lay out with offsets decreasing from the end of the allocation
  380               totalOffset = allocated;
  381               for (int i = 0; i < spans.length; i++) {
  382                   SizeRequirements req = request[i];
  383                   int play = (int)(factor * (req.maximum - req.preferred));
  384                   spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
  385                   offsets[i] = totalOffset - spans[i];
  386                   totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
  387               }
  388           }
  389       }
  390   
  391       /**
  392        * Creates a bunch of offset/span pairs specifying how to
  393        * lay out a set of components with the specified alignments.
  394        * The resulting span allocations will overlap, with each one
  395        * fitting as well as possible into the given total allocation.
  396        * This method requires that you specify
  397        * the total amount of space to be allocated,
  398        * the size requirements for each component to be placed
  399        * (specified as an array of SizeRequirements), and
  400        * the total size requirements of the set of components
  401        * (only the alignment field of which is actually used).
  402        * You can get the total size requirement by invoking
  403        * getAlignedSizeRequirements.
  404        *
  405        * Normal alignment will be done with an alignment value of 0.0f
  406        * representing the left/top edge of a component.
  407        *
  408        * @param allocated the total span to be allocated >= 0.
  409        * @param total     the total of the children requests.
  410        * @param children  the size requirements for each component.
  411        * @param offsets   the offset from 0 for each child where
  412        *   the spans were allocated (determines placement of the span).
  413        * @param spans     the span allocated for each child to make the
  414        *   total target span.
  415        */
  416       public static void calculateAlignedPositions(int allocated,
  417                                                    SizeRequirements total,
  418                                                    SizeRequirements[] children,
  419                                                    int[] offsets,
  420                                                    int[] spans) {
  421           calculateAlignedPositions( allocated, total, children, offsets, spans, true );
  422       }
  423   
  424       /**
  425        * Creates a set of offset/span pairs specifying how to
  426        * lay out a set of components with the specified alignments.
  427        * The resulting span allocations will overlap, with each one
  428        * fitting as well as possible into the given total allocation.
  429        * This method requires that you specify
  430        * the total amount of space to be allocated,
  431        * the size requirements for each component to be placed
  432        * (specified as an array of SizeRequirements), and
  433        * the total size requirements of the set of components
  434        * (only the alignment field of which is actually used)
  435        * You can get the total size requirement by invoking
  436        * getAlignedSizeRequirements.
  437        *
  438        * This method also requires a flag indicating whether normal or
  439        * reverse alignment should be performed.  With normal alignment
  440        * the value 0.0f represents the left/top edge of the component
  441        * to be aligned.  With reverse alignment, 0.0f represents the
  442        * right/bottom edge.
  443        *
  444        * @param allocated the total span to be allocated >= 0.
  445        * @param total     the total of the children requests.
  446        * @param children  the size requirements for each component.
  447        * @param offsets   the offset from 0 for each child where
  448        *   the spans were allocated (determines placement of the span).
  449        * @param spans     the span allocated for each child to make the
  450        *   total target span.
  451        * @param normal    when true, the alignment value 0.0f means
  452        *   left/top; when false, it means right/bottom.
  453        * @since 1.4
  454        */
  455       public static void calculateAlignedPositions(int allocated,
  456                                                    SizeRequirements total,
  457                                                    SizeRequirements[] children,
  458                                                    int[] offsets,
  459                                                    int[] spans,
  460                                                    boolean normal) {
  461           float totalAlignment = normal ? total.alignment : 1.0f - total.alignment;
  462           int totalAscent = (int)(allocated * totalAlignment);
  463           int totalDescent = allocated - totalAscent;
  464           for (int i = 0; i < children.length; i++) {
  465               SizeRequirements req = children[i];
  466               float alignment = normal ? req.alignment : 1.0f - req.alignment;
  467               int maxAscent = (int)(req.maximum * alignment);
  468               int maxDescent = req.maximum - maxAscent;
  469               int ascent = Math.min(totalAscent, maxAscent);
  470               int descent = Math.min(totalDescent, maxDescent);
  471   
  472               offsets[i] = totalAscent - ascent;
  473               spans[i] = (int) Math.min((long) ascent + (long) descent, Integer.MAX_VALUE);
  474           }
  475       }
  476   
  477       // This method was used by the JTable - which now uses a different technique.
  478       /**
  479        * Adjust a specified array of sizes by a given amount.
  480        *
  481        * @param delta     an int specifying the size difference
  482        * @param children  an array of SizeRequirements objects
  483        * @return an array of ints containing the final size for each item
  484        */
  485       public static int[] adjustSizes(int delta, SizeRequirements[] children) {
  486         return new int[0];
  487       }
  488   }

Home » openjdk-7 » javax » swing » [javadoc | source]