/[classpath]/classpath/javax/swing/BoxLayout.java
ViewVC logotype

Diff of /classpath/javax/swing/BoxLayout.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.12 by rabbit78, Fri Jun 24 14:39:49 2005 UTC revision 1.13 by rabbit78, Mon Jun 27 14:41:10 2005 UTC
# Line 45  import java.awt.Dimension; Line 45  import java.awt.Dimension;
45  import java.awt.Insets;  import java.awt.Insets;
46  import java.awt.LayoutManager2;  import java.awt.LayoutManager2;
47  import java.io.Serializable;  import java.io.Serializable;
48    import java.util.Collection;
49    import java.util.Iterator;
50    import java.util.Vector;
51    
52  import gnu.java.awt.AWTUtilities;  import gnu.java.awt.AWTUtilities;
53    
# Line 52  import gnu.java.awt.AWTUtilities; Line 55  import gnu.java.awt.AWTUtilities;
55   * A layout for swing components.   * A layout for swing components.
56   *   *
57   * @author Ronald Veldema (rveldema@cs.vu.nl)   * @author Ronald Veldema (rveldema@cs.vu.nl)
58     * @author Roman Kennke (roman@kennke.org)
59   */   */
60  public class BoxLayout implements LayoutManager2, Serializable  public class BoxLayout implements LayoutManager2, Serializable
61  {  {
62    
63      /**
64       * This is an abstraction that allows the BoxLayout algorithm to
65       * be applied to both direction (X and Y) without duplicating the
66       * algorithm. It defines several methods that access properties of
67       * a component for a specific direction.
68       */
69      static interface Direction
70      {
71        /**
72         * Returns the correct part of <code>d</code> for this direction. This will
73         * be <code>d.width</code> for horizontal and <code>d.height</code> for
74         * vertical direction.
75         *
76         * @param d the size as Dimension object
77         *
78         * @return the correct part of <code>d</code> for this direction
79         */
80        int size(Dimension d);
81    
82        /**
83         * Returns the lower bounds of the {@link Insets} object according to this
84         * direction. This will be <code>insets.top</code> for vertical direction
85         * and <code>insets.left</code> for horizontal direction.
86         *
87         * @param the {@link Insets} object from which to return the lower bounds
88         *
89         * @return the lower bounds of the {@link Insets} object according to this
90         *     direction
91         */
92        int lower(Insets insets);
93    
94        /**
95         * Returns the alignment property according to this direction.
96         *
97         * @param comp the Component for which to return the alignment property
98         *
99         * @return the alignment property according to this direction
100         */
101        float alignment(Component comp);
102    
103        /**
104         * Sets the location for Component <code>c</code>. <code>coord1</code>
105         * specifies the coordinate of the location in this direction,
106         * <code>coord2</code> the coordinate of the location in the opposite
107         * direction.
108         *
109         * @param c the Component for which to set the location
110         * @param coord1 the coordinate in this direction
111         * @param coord2 the coordinate in the opposite direction
112         */
113        void setLocation(Component c, int coord1, int coord2);
114    
115        /**
116         * Sets the size for Component <code>c</code>. <code>coord1</code>
117         * specifies the size in this direction,
118         * <code>coord2</code> the size in the opposite
119         * direction.
120         *
121         * @param c the Component for which to set the size
122         * @param size1 the size in this direction
123         * @param size2 the size in the opposite direction
124         */
125        void setSize(Component c, int size1, int size2);
126      }
127    
128      /**
129       * The horizontal direction.
130       */
131      static class Horizontal implements Direction
132      {
133        /**
134         * Returns the correct part of <code>d</code> for this direction. This will
135         * be <code>d.width</code> for horizontal and <code>d.height</code> for
136         * vertical direction.
137         *
138         * @param d the size as Dimension object
139         *
140         * @return the correct part of <code>d</code> for this direction
141         */
142        public int size(Dimension d)
143        {
144          return d.width;
145        }
146    
147        /**
148         * Returns the lower bounds of the {@link Insets} object according to this
149         * direction. This will be <code>insets.top</code> for vertical direction
150         * and <code>insets.left</code> for horizontal direction.
151         *
152         * @param the {@link Insets} object from which to return the lower bounds
153         *
154         * @return the lower bounds of the {@link Insets} object according to this
155         *     direction
156         */
157        public int lower(Insets insets)
158        {
159          return insets.left;
160        }
161    
162        /**
163         * Returns the alignment property according to this direction.
164         *
165         * @param comp the Component for which to return the alignment property
166         *
167         * @return the alignment property according to this direction
168         */
169        public float alignment(Component comp)
170        {
171          return comp.getAlignmentX();
172        }
173    
174        /**
175         * Sets the location for Component <code>c</code>. <code>coord1</code>
176         * specifies the coordinate of the location in this direction,
177         * <code>coord2</code> the coordinate of the location in the opposite
178         * direction.
179         *
180         * @param c the Component for which to set the location
181         * @param coord1 the coordinate in this direction
182         * @param coord2 the coordinate in the opposite direction
183         */
184        public void setLocation(Component c, int coord1, int coord2)
185        {
186          c.setLocation(coord1, coord2);
187        }
188    
189        /**
190         * Sets the size for Component <code>c</code>. <code>coord1</code>
191         * specifies the size in this direction,
192         * <code>coord2</code> the size in the opposite
193         * direction.
194         *
195         * @param c the Component for which to set the size
196         * @param size1 the size in this direction
197         * @param size2 the size in the opposite direction
198         */
199        public void setSize(Component c, int size1, int size2)
200        {
201          c.setSize(size1, size2);
202        }
203      }
204      /**
205       * The vertical direction.
206       */
207      static class Vertical implements Direction
208      {
209        /**
210         * Returns the correct part of <code>d</code> for this direction. This will
211         * be <code>d.width</code> for horizontal and <code>d.height</code> for
212         * vertical direction.
213         *
214         * @param d the size as Dimension object
215         *
216         * @return the correct part of <code>d</code> for this direction
217         */
218        public int size(Dimension d)
219        {
220          return d.height;
221        }
222    
223        /**
224         * Returns the lower bounds of the {@link Insets} object according to this
225         * direction. This will be <code>insets.top</code> for vertical direction
226         * and <code>insets.left</code> for horizontal direction.
227         *
228         * @param the {@link Insets} object from which to return the lower bounds
229         *
230         * @return the lower bounds of the {@link Insets} object according to this
231         *     direction
232         */
233        public int lower(Insets insets)
234        {
235          return insets.top;
236        }
237    
238        /**
239         * Returns the alignment property according to this direction.
240         *
241         * @param comp the Component for which to return the alignment property
242         *
243         * @return the alignment property according to this direction
244         */
245        public float alignment(Component comp)
246        {
247          return comp.getAlignmentY();
248        }
249    
250        /**
251         * Sets the location for Component <code>c</code>. <code>coord1</code>
252         * specifies the coordinate of the location in this direction,
253         * <code>coord2</code> the coordinate of the location in the opposite
254         * direction.
255         *
256         * @param c the Component for which to set the location
257         * @param coord1 the coordinate in this direction
258         * @param coord2 the coordinate in the opposite direction
259         */
260        public void setLocation(Component c, int coord1, int coord2)
261        {
262          c.setLocation(coord2, coord1);
263        }
264    
265        /**
266         * Sets the size for Component <code>c</code>. <code>coord1</code>
267         * specifies the size in this direction,
268         * <code>coord2</code> the size in the opposite
269         * direction.
270         *
271         * @param c the Component for which to set the size
272         * @param size1 the size in this direction
273         * @param size2 the size in the opposite direction
274         */
275        public void setSize(Component c, int size1, int size2)
276        {
277          c.setSize(size2, size1);
278        }
279      }
280    
281      /**
282       * A helper class that temporarily stores the size specs of a component.
283       */
284      static class SizeReq
285      {
286        int size;
287        int min;
288        int pref;
289        int max;
290        float align;
291        Component comp;
292        SizeReq(Component comp, Direction dir)
293        {
294          this.min = dir.size(comp.getMinimumSize());
295          this.pref = dir.size(comp.getPreferredSize());
296          this.max = dir.size(comp.getMaximumSize());
297          this.size = dir.size(comp.getSize());
298          this.align = dir.alignment(comp);
299          this.comp = comp;
300        }
301      }
302    
303    /**    /**
304     * Specifies that components are laid out left to right.     * Specifies that components are laid out left to right.
305     */     */
# Line 90  public class BoxLayout implements Layout Line 335  public class BoxLayout implements Layout
335     */     */
336    private int way = X_AXIS;    private int way = X_AXIS;
337    
338      /** Constant for the horizontal direction. */
339      private static final Direction HORIZONTAL = new Horizontal();
340    
341      /** Constant for the vertical direction. */
342      private static final Direction VERTICAL = new Vertical();
343    
344    /**    /**
345     * Constructs a <code>BoxLayout</code> object.     * Constructs a <code>BoxLayout</code> object.
346     *     *
# Line 240  public class BoxLayout implements Layout Line 491  public class BoxLayout implements Layout
491     */     */
492    public void layoutContainer(Container parent)    public void layoutContainer(Container parent)
493    {    {
     if (parent != container)  
       throw new AWTError("invalid parent");  
   
     Dimension size = parent.getSize();  
     Insets insets = parent.getInsets();  
     Dimension innerSize = new Dimension(size.width - insets.left  
                                         - insets.right, size.height  
                                         - insets.bottom - insets.top);  
     Component[] children = AWTUtilities.getVisibleChildren(parent);  
     boolean[] laidOut = new boolean[children.length];  
     for (int index = 0; index < laidOut.length; index++)  
       laidOut[index] = false;  
   
494      if (isHorizontalIn(parent))      if (isHorizontalIn(parent))
495        {        layoutAlgorithm(parent, HORIZONTAL, VERTICAL);
         // compute overall preferred width  
         int preferredWidthAll = 0;  
         for (int index = 0; index < children.length; index++)  
           {  
             preferredWidthAll += children[index].getPreferredSize().width;  
           }  
         double widthFactor = (double) innerSize.width /  
           (double) preferredWidthAll;  
   
         // sort out components that are constrained by minimum or maximum size  
         int widthRemain = innerSize.width;  
         for (int index = 0; index < children.length; index++)  
           {  
             Component comp = children[index];  
             Dimension sz = comp.getPreferredSize();  
             Dimension minSize = comp.getMinimumSize();  
             Dimension maxSize = comp.getMaximumSize();  
             int width = (int) (sz.width * widthFactor);  
             int height = Math.min(innerSize.height, maxSize.height);  
             // check min size  
             if (width < minSize.width)  
               {  
                 width = minSize.width;  
                 comp.setSize(width, height);  
                 laidOut[index] = true;  
                 preferredWidthAll -= sz.width;  
                 widthRemain -= width;  
                 continue;  
               }  
             // check max size  
             if (width > maxSize.width)  
               {  
                 width = maxSize.width;  
                 comp.setSize(width, height);  
                 laidOut[index] = true;  
                 preferredWidthAll -= sz.width;  
                 widthRemain -= width;  
                 continue;  
               }  
   
           }  
   
         // recompute widthFactor for remaining components  
         widthFactor = (double) widthRemain / (double) preferredWidthAll;  
   
         int x = insets.left;  
   
         // lay out remaining comonents  
         for (int index = 0; index < children.length; index++)  
           {  
             Component comp = children[index];  
             int width = 0;  
   
             if (!laidOut[index])  
               {  
                 Dimension sz = comp.getPreferredSize();  
                 Dimension maxSize = comp.getMaximumSize();  
                 width = (int) (sz.width * widthFactor);  
                 int height = Math.min(innerSize.height, maxSize.height);  
                 comp.setSize(width, height);  
               }  
             else  
                 width = comp.getWidth();  
   
             int cy = (int) ((innerSize.height - comp.getHeight())  
               * comp.getAlignmentY() + insets.top);  
             comp.setLocation(x, cy);  
             x = x + width;              
           }  
       }  
496      else      else
497        {        layoutAlgorithm(parent, VERTICAL, HORIZONTAL);
         // compute overall preferred height  
         int preferredHeightAll = 0;  
         for (int index = 0; index < children.length; index++)  
           {  
             preferredHeightAll += children[index].getPreferredSize().height;  
           }  
         double heightFactor = (double) innerSize.height /  
           (double) preferredHeightAll;  
   
         // sort out components that are constrained by minimum or maximum size  
         int heightRemain = innerSize.height;  
         for (int index = 0; index < children.length; index++)  
           {  
             Component comp = children[index];  
             Dimension sz = comp.getPreferredSize();  
             Dimension minSize = comp.getMinimumSize();  
             Dimension maxSize = comp.getMaximumSize();  
             int height = (int) (sz.height * heightFactor);  
             int width = Math.min(innerSize.width, maxSize.width);  
             // check min size  
             if (height < minSize.height)  
               {  
                 height = minSize.height;  
                 comp.setSize(width, height);  
                 laidOut[index] = true;  
                 preferredHeightAll -= sz.height;  
                 heightRemain -= height;  
                 continue;  
               }  
             // check max size  
             if (height > maxSize.height)  
               {  
                 height = maxSize.height;  
                 comp.setSize(width, height);  
                 laidOut[index] = true;  
                 preferredHeightAll -= sz.height;  
                 heightRemain -= height;  
                 continue;  
               }  
   
           }  
   
         // recompute heightFactor for remaining components  
         heightFactor = (double) heightRemain / (double) preferredHeightAll;  
   
         int y = insets.top;  
   
         // lay out remaining comonents  
         for (int index = 0; index < children.length; index++)  
           {  
             Component comp = children[index];  
             int height = 0;  
   
             if (!laidOut[index])  
               {  
                 Dimension sz = comp.getPreferredSize();  
                 Dimension maxSize = comp.getMaximumSize();  
                 height = (int) (sz.height * heightFactor);  
                 int width = Math.min(innerSize.width, maxSize.width);  
                 comp.setSize(width, height);  
               }  
             else  
               height = comp.getHeight();  
   
             int cx = (int) ((innerSize.width - comp.getWidth())  
               * comp.getAlignmentX() + insets.left);  
             comp.setLocation(cx, y);  
             y = y + height;              
           }  
       }      
498    }    }
499        
500    /**    /**
# Line 502  public class BoxLayout implements Layout Line 600  public class BoxLayout implements Layout
600        }        }
601      return new Dimension(x, y);      return new Dimension(x, y);
602    }    }
603    
604      /**
605       * Lays out the Container <code>c</code> in the layout direction
606       * <code>layoutDir</code>. The direction that is crossing the layout
607       * direction is specified in <code>crossDir</code>.
608       *
609       * @param parent
610       * @param layoutDir
611       * @param crossDir
612       */
613      void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir)
614      {
615        if (parent != container)
616          throw new AWTError("invalid parent");
617    
618        Dimension parentSize = parent.getSize();
619        Insets insets = parent.getInsets();
620        Dimension innerSize = new Dimension(parentSize.width - insets.left
621                                            - insets.right, parentSize.height
622                                            - insets.bottom - insets.top);
623    
624        // Set all components to their preferredSizes and sum up the allocated
625        // space. Create SizeReqs for each component and store them in
626        // sizeReqs. Find the maximum size in the crossing direction.
627        Component[] children = AWTUtilities.getVisibleChildren(parent);
628        Vector sizeReqs = new Vector();
629        int allocated = 0;
630        for (int i = 0; i < children.length; i++)
631          {
632            Component c = children[i];
633            SizeReq sizeReq = new SizeReq(c, layoutDir);
634            int preferred = layoutDir.size(c.getPreferredSize());
635            sizeReq.size = preferred;
636            allocated += preferred;
637            sizeReqs.add(sizeReq);
638          }
639    
640        // Distribute remaining space (may be positive or negative) over components
641        int remainder = layoutDir.size(innerSize) - allocated;
642        distributeSpace(sizeReqs, remainder, layoutDir);
643    
644        // Resize and relocate components. If the component can be sized to
645        // take the full space in the crossing direction, then do so, otherwise
646        // align according to its alingnmentX or alignmentY property.
647        int loc = 0;
648        int offset1 = layoutDir.lower(insets);
649        int offset2 = crossDir.lower(insets);
650        for (Iterator i = sizeReqs.iterator(); i.hasNext();)
651          {
652            SizeReq sizeReq = (SizeReq) i.next();
653            Component c = sizeReq.comp;
654            int availCrossSize = crossDir.size(innerSize);
655            int maxCross = crossDir.size(c.getMaximumSize());
656            int crossSize = Math.min(availCrossSize, maxCross);
657            int crossRemainder = availCrossSize - crossSize;
658            int crossLoc = (int) (crossDir.alignment(c) * crossRemainder);
659            layoutDir.setSize(c, sizeReq.size, crossSize);
660            layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc);
661            loc += sizeReq.size;
662          }
663      }
664    
665      /**
666       * Distributes some space over a set of components. This implementation
667       * tries to set the components as close as possible to their
668       * <code>preferredSize</code>s, and respects the components
669       * <code>minimumSize</code> and <code>maximumSize</code>.
670       *
671       * The algorithm is implemented as follows:
672       *
673       * <ul>
674       * <li>The <code>remainder</code> is divided by the number of components
675       * in <code>freeComponents</code>.</li>
676       * <li>The result is added to (or substracted from) the size of each
677       * component.</li>
678       * <li>If the <code>minimumSize</code> or <code>maximumSize</code> of a
679       * component is exceeded, then this component is set to its
680       * <code>minimumSize</code> or <code>maximumSize</code>, it is removed from
681       * <code>freeComponents</code> and the difference is added to a new
682       * remainder.</li>
683       * <li>Finally, if there is a new remainer != 0 and the
684       * <code>freeComponents.size() != 0</code>, then this method is called
685       * recursivly to distribute the newly allocated remaining space.</li>
686       * </ul>
687       *
688       * @param freeComponents a SizeReq collection for components that have space
689       *     left so that they can be moved freely
690       * @param remainder the space that should be distributed between the
691       *     components
692       * @param dir the direction in which we operate
693       */
694      void distributeSpace(Collection freeComponents, int remainder, Direction dir)
695      {
696        // Sum up total available space in components. If the remainder is negative
697        // then we sum up the difference between minSize and size. If remainder
698        // is positive we sum up the difference between maxSize and size.
699        double totalAvailable = 0;
700        for (Iterator i = freeComponents.iterator(); i.hasNext();)
701          {
702            SizeReq sizeReq = (SizeReq) i.next();
703            if (remainder >= 0)
704              totalAvailable += sizeReq.max - sizeReq.size;
705            else
706              totalAvailable += sizeReq.min - sizeReq.size;
707          }
708        if (totalAvailable == 0)
709          if (remainder >= 0)
710            totalAvailable = 1;
711          else
712            totalAvailable = -1;
713    
714        int newRemainder = 0;
715        Vector stillFree = new Vector();
716        for (Iterator i = freeComponents.iterator(); i.hasNext();)
717          {
718            // Add/substract share to component.
719            SizeReq sizeReq = (SizeReq) i.next();
720            double available = 0;
721            if (remainder >= 0)
722              available = sizeReq.max - sizeReq.size;
723            else
724              available = sizeReq.min - sizeReq.size;
725            int share = (int) ((available / totalAvailable) * remainder);
726            sizeReq.size += share;
727            // check for min/maximumSize
728            if (sizeReq.size < sizeReq.min)
729              {
730                newRemainder += sizeReq.size - sizeReq.min;
731                sizeReq.size = sizeReq.min;
732              }
733            else if (sizeReq.size > sizeReq.max)
734              {
735                newRemainder += sizeReq.size - sizeReq.max;
736                sizeReq.size = sizeReq.max;
737              }
738            else
739              stillFree.add(sizeReq);
740          }
741        // recursivly call this method if necessary
742        if (newRemainder != 0 && stillFree.size() > 0)
743          distributeSpace(stillFree, newRemainder, dir);
744      }
745  }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26