Index: javax/swing/SizeRequirements.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/SizeRequirements.java,v retrieving revision 1.11 diff -u -r1.11 SizeRequirements.java --- javax/swing/SizeRequirements.java 13 Sep 2005 10:23:50 -0000 1.11 +++ javax/swing/SizeRequirements.java 25 Sep 2005 10:11:14 -0000 @@ -166,7 +166,31 @@ public static SizeRequirements getAlignedSizeRequirements(SizeRequirements[] children) { - return null; // TODO + 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 - myMinLeft; + prefLeft = Math.max(myPrefLeft, prefLeft); + prefRight = Math.max(myPrefRight, prefRight); + float myMaxLeft = children[i].maximum * children[i].alignment; + float myMaxRight = children[i].maximum - myMinLeft; + 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); + return new SizeRequirements(minSize, prefSize, maxSize, 0.5F); } /** @@ -317,11 +341,24 @@ int[] offset, int[] spans, boolean forward) { - // TODO: Implement this correctly. - for (int i = 0; i < children.length; ++i) + // First we compute the position of the baseline. + float left = 0; + float right = 0; + for (int i = 0; i < children.length; i++) + { + float myLeft = children[i].preferred * children[i].alignment; + float myRight = children[i].preferred - myLeft; + left = Math.max(myLeft, left); + right = Math.max(myRight, right); + } + int baseline = (int) ((left / (left + right)) * allocated); + // Now we can layout the components along the baseline. + for (int i = 0; i < children.length; i++) { - // This is only a hack to make things work a little. - spans[i] = Math.min(allocated, children[i].maximum); + // FIXME: Handle the case when span[i] results in exceeding + // the available space. + spans[i] = children[i].preferred; + offset[i] = baseline - (int) (children[i].alignment * ((float) spans[i])); } } Index: javax/swing/BoxLayout.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/BoxLayout.java,v retrieving revision 1.17 diff -u -r1.17 BoxLayout.java --- javax/swing/BoxLayout.java 26 Jul 2005 15:30:54 -0000 1.17 +++ javax/swing/BoxLayout.java 25 Sep 2005 10:11:14 -0000 @@ -45,7 +45,6 @@ import java.awt.Insets; import java.awt.LayoutManager2; import java.io.Serializable; -import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -63,248 +62,6 @@ { /** - * This is an abstraction that allows the BoxLayout algorithm to - * be applied to both direction (X and Y) without duplicating the - * algorithm. It defines several methods that access properties of - * a component for a specific direction. - */ - static interface Direction - { - /** - * Returns the correct part of d for this direction. This will - * be d.width for horizontal and d.height for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of d for this direction - */ - int size(Dimension d); - - /** - * Returns the lower bounds of the address@hidden Insets} object according to this - * direction. This will be insets.top for vertical direction - * and insets.left for horizontal direction. - * - * @param the address@hidden Insets} object from which to return the lower bounds - * - * @return the lower bounds of the address@hidden Insets} object according to this - * direction - */ - int lower(Insets insets); - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - float alignment(Component comp); - - /** - * Sets the location for Component c. coord1 - * specifies the coordinate of the location in this direction, - * coord2 the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - void setLocation(Component c, int coord1, int coord2); - - /** - * Sets the size for Component c. coord1 - * specifies the size in this direction, - * coord2 the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - void setSize(Component c, int size1, int size2); - } - - /** - * The horizontal direction. - */ - static class Horizontal implements Direction - { - /** - * Returns the correct part of d for this direction. This will - * be d.width for horizontal and d.height for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of d for this direction - */ - public int size(Dimension d) - { - return d.width; - } - - /** - * Returns the lower bounds of the address@hidden Insets} object according to this - * direction. This will be insets.top for vertical direction - * and insets.left for horizontal direction. - * - * @param insets the address@hidden Insets} object from which to return the lower - * bounds - * - * @return the lower bounds of the address@hidden Insets} object according to this - * direction - */ - public int lower(Insets insets) - { - return insets.left; - } - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - public float alignment(Component comp) - { - return comp.getAlignmentX(); - } - - /** - * Sets the location for Component c. coord1 - * specifies the coordinate of the location in this direction, - * coord2 the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - public void setLocation(Component c, int coord1, int coord2) - { - c.setLocation(coord1, coord2); - } - - /** - * Sets the size for Component c. coord1 - * specifies the size in this direction, - * coord2 the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - public void setSize(Component c, int size1, int size2) - { - c.setSize(size1, size2); - } - } - /** - * The vertical direction. - */ - static class Vertical implements Direction - { - /** - * Returns the correct part of d for this direction. This will - * be d.width for horizontal and d.height for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of d for this direction - */ - public int size(Dimension d) - { - return d.height; - } - - /** - * Returns the lower bounds of the address@hidden Insets} object according to this - * direction. This will be insets.top for vertical direction - * and insets.left for horizontal direction. - * - * @param insets the address@hidden Insets} object from which to return the lower - * bounds - * - * @return the lower bounds of the address@hidden Insets} object according to this - * direction - */ - public int lower(Insets insets) - { - return insets.top; - } - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - public float alignment(Component comp) - { - return comp.getAlignmentY(); - } - - /** - * Sets the location for Component c. coord1 - * specifies the coordinate of the location in this direction, - * coord2 the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - public void setLocation(Component c, int coord1, int coord2) - { - c.setLocation(coord2, coord1); - } - - /** - * Sets the size for Component c. coord1 - * specifies the size in this direction, - * coord2 the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - public void setSize(Component c, int size1, int size2) - { - c.setSize(size2, size1); - } - } - - /** - * A helper class that temporarily stores the size specs of a component. - */ - static class SizeReq - { - int size; - int min; - int pref; - int max; - float align; - Component comp; - SizeReq(Component comp, Direction dir) - { - this.min = dir.size(comp.getMinimumSize()); - this.pref = dir.size(comp.getPreferredSize()); - this.max = dir.size(comp.getMaximumSize()); - this.size = dir.size(comp.getSize()); - this.align = dir.alignment(comp); - this.comp = comp; - } - } - - /** * Specifies that components are laid out left to right. */ public static final int X_AXIS = 0; @@ -339,12 +96,6 @@ */ private int way = X_AXIS; - /** Constant for the horizontal direction. */ - private static final Direction HORIZONTAL = new Horizontal(); - - /** Constant for the vertical direction. */ - private static final Direction VERTICAL = new Vertical(); - /** * Constructs a BoxLayout object. * @@ -404,42 +155,24 @@ if (parent != container) throw new AWTError("invalid parent"); - Insets insets = parent.getInsets(); - int x = 0; - int y = 0; - - List children = AWTUtilities.getVisibleChildren(parent); - - if (isHorizontalIn(parent)) - { - x = insets.left + insets.right; - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getPreferredSize(); - x += sz.width; - y = Math.max(y, sz.height); - } - y += insets.bottom + insets.top; - } - else - { - y = insets.top + insets.bottom; - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getPreferredSize(); - y += sz.height; - x = Math.max(x, sz.width); - } - x += insets.left + insets.right; + // Setup the SizeRequirements for both the X and Y axis. + Component[] children = container.getComponents(); + SizeRequirements[] hSizeReqs = new SizeRequirements[children.length]; + SizeRequirements[] vSizeReqs = new SizeRequirements[children.length]; + getSizeRequirements(hSizeReqs, vSizeReqs); + SizeRequirements hReq; + SizeRequirements vReq; + if (isHorizontalIn(container)) + { + hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs); } - - return new Dimension(x, y); + else + { + hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs); + } + return new Dimension(hReq.preferred, vReq.preferred); } /** @@ -454,38 +187,24 @@ if (parent != container) throw new AWTError("invalid parent"); - Insets insets = parent.getInsets(); - int x = insets.left + insets.right; - int y = insets.bottom + insets.top; - - List children = AWTUtilities.getVisibleChildren(parent); - - if (isHorizontalIn(parent)) + // Setup the SizeRequirements for both the X and Y axis. + Component[] children = container.getComponents(); + SizeRequirements[] hSizeReqs = new SizeRequirements[children.length]; + SizeRequirements[] vSizeReqs = new SizeRequirements[children.length]; + getSizeRequirements(hSizeReqs, vSizeReqs); + SizeRequirements hReq; + SizeRequirements vReq; + if (isHorizontalIn(container)) { - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMinimumSize(); - x += sz.width; - y = Math.max(y, sz.height); - } + hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs); } else { - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMinimumSize(); - y += sz.height; - x = Math.max(x, sz.width); - } + hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs); } - - return new Dimension(x, y); + return new Dimension(hReq.minimum, vReq.minimum); } /** @@ -495,10 +214,38 @@ */ public void layoutContainer(Container parent) { - if (isHorizontalIn(parent)) - layoutAlgorithm(parent, HORIZONTAL, VERTICAL); + // Setup the SizeRequirements for both the X and Y axis. + Component[] children = container.getComponents(); + SizeRequirements[] hSizeReqs = new SizeRequirements[children.length]; + SizeRequirements[] vSizeReqs = new SizeRequirements[children.length]; + getSizeRequirements(hSizeReqs, vSizeReqs); + + int[] hSpans = new int[children.length]; + int[] hOffsets = new int[children.length]; + int[] vSpans = new int[children.length]; + int[] vOffsets = new int[children.length]; + + if (isHorizontalIn(container)) + { + SizeRequirements.calculateTiledPositions(container.getWidth(), null, + hSizeReqs, hOffsets, hSpans); + SizeRequirements.calculateAlignedPositions(container.getHeight(), null, + vSizeReqs, vOffsets, vSpans); + } else - layoutAlgorithm(parent, VERTICAL, HORIZONTAL); + { + SizeRequirements.calculateTiledPositions(container.getHeight(), null, + vSizeReqs, vOffsets, vSpans); + SizeRequirements.calculateAlignedPositions(container.getWidth(), null, + hSizeReqs, hOffsets, hSpans); + } + + // Set positions and widths of child components. + for (int i = 0; i < children.length; i++) + { + Component child = children[i]; + child.setBounds(hOffsets[i], vOffsets[i], hSpans[i], vSpans[i]); + } } /** @@ -565,185 +312,61 @@ if (parent != container) throw new AWTError("invalid parent"); - Insets insets = parent.getInsets(); - int x = insets.left + insets.right; - int y = insets.top + insets.bottom; - - List children = AWTUtilities.getVisibleChildren(parent); - - if (isHorizontalIn(parent)) + // Setup the SizeRequirements for both the X and Y axis. + Component[] children = container.getComponents(); + SizeRequirements[] hSizeReqs = new SizeRequirements[children.length]; + SizeRequirements[] vSizeReqs = new SizeRequirements[children.length]; + getSizeRequirements(hSizeReqs, vSizeReqs); + SizeRequirements hReq; + SizeRequirements vReq; + if (isHorizontalIn(container)) { - - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMaximumSize(); - x += sz.width; - // Check for overflow. - if (x < 0) - x = Integer.MAX_VALUE; - y = Math.max(y, sz.height); - } + hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs); } else { - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMaximumSize(); - y += sz.height; - // Check for overflow - if (y < 0) - y = Integer.MAX_VALUE; - x = Math.max(x, sz.width); - } - } - return new Dimension(x, y); + hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs); + vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs); + } + return new Dimension(hReq.maximum, vReq.maximum); } /** - * Lays out the Container c in the layout direction - * layoutDir. The direction that is crossing the layout - * direction is specified in crossDir. + * Fills arrays of SizeRequirements for the horizontal and vertical + * requirements of the children of component. * - * @param parent - * @param layoutDir - * @param crossDir + * @param hSizeReqs the horizontal requirements to be filled by this method + * @param vSizeReqs the vertical requirements to be filled by this method */ - void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir) + private void getSizeRequirements(SizeRequirements[] hSizeReqs, + SizeRequirements[] vSizeReqs) { - if (parent != container) - throw new AWTError("invalid parent"); - - Dimension parentSize = parent.getSize(); - Insets insets = parent.getInsets(); - Dimension innerSize = new Dimension(parentSize.width - insets.left - - insets.right, parentSize.height - - insets.bottom - insets.top); - - // Set all components to their preferredSizes and sum up the allocated - // space. Create SizeReqs for each component and store them in - // sizeReqs. Find the maximum size in the crossing direction. - List children = AWTUtilities.getVisibleChildren(parent); - Vector sizeReqs = new Vector(); - int allocated = 0; - for (Iterator i = children.iterator(); i.hasNext();) + Component[] children = container.getComponents(); + for (int i = 0; i < children.length; i++) { - Component c = (Component) i.next(); - SizeReq sizeReq = new SizeReq(c, layoutDir); - int preferred = layoutDir.size(c.getPreferredSize()); - sizeReq.size = preferred; - allocated += preferred; - sizeReqs.add(sizeReq); - } - - // Distribute remaining space (may be positive or negative) over components - int remainder = layoutDir.size(innerSize) - allocated; - distributeSpace(sizeReqs, remainder, layoutDir); - - // Resize and relocate components. If the component can be sized to - // take the full space in the crossing direction, then do so, otherwise - // align according to its alingnmentX or alignmentY property. - int loc = 0; - int offset1 = layoutDir.lower(insets); - int offset2 = crossDir.lower(insets); - for (Iterator i = sizeReqs.iterator(); i.hasNext();) - { - SizeReq sizeReq = (SizeReq) i.next(); - Component c = sizeReq.comp; - int availCrossSize = crossDir.size(innerSize); - int maxCross = crossDir.size(c.getMaximumSize()); - int crossSize = Math.min(availCrossSize, maxCross); - int crossRemainder = availCrossSize - crossSize; - int crossLoc = (int) (crossDir.alignment(c) * crossRemainder); - layoutDir.setSize(c, sizeReq.size, crossSize); - layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc); - loc += sizeReq.size; - } - } - - /** - * Distributes some space over a set of components. This implementation - * tries to set the components as close as possible to their - * preferredSizes, and respects the components - * minimumSize and maximumSize. - * - * The algorithm is implemented as follows: - * - * - * - * @param freeComponents a SizeReq collection for components that have space - * left so that they can be moved freely - * @param remainder the space that should be distributed between the - * components - * @param dir the direction in which we operate - */ - void distributeSpace(Collection freeComponents, int remainder, Direction dir) - { - // Sum up total available space in components. If the remainder is negative - // then we sum up the difference between minSize and size. If remainder - // is positive we sum up the difference between maxSize and size. - double totalAvailable = 0; - for (Iterator i = freeComponents.iterator(); i.hasNext();) - { - SizeReq sizeReq = (SizeReq) i.next(); - if (remainder >= 0) - totalAvailable += sizeReq.max - sizeReq.size; - else - totalAvailable += sizeReq.min - sizeReq.size; - } - if (totalAvailable == 0) - if (remainder >= 0) - totalAvailable = 1; - else - totalAvailable = -1; - - int newRemainder = 0; - Vector stillFree = new Vector(); - for (Iterator i = freeComponents.iterator(); i.hasNext();) - { - // Add/substract share to component. - SizeReq sizeReq = (SizeReq) i.next(); - double available = 0; - if (remainder >= 0) - available = sizeReq.max - sizeReq.size; + Component child = children[i]; + if (! child.isVisible()) + { + SizeRequirements req = new SizeRequirements(); + hSizeReqs[i] = req; + vSizeReqs[i] = req; + } else - available = sizeReq.min - sizeReq.size; - int share = (int) ((available / totalAvailable) * remainder); - sizeReq.size += share; - // check for min/maximumSize - if (sizeReq.size < sizeReq.min) - { - newRemainder += sizeReq.size - sizeReq.min; - sizeReq.size = sizeReq.min; - } - else if (sizeReq.size > sizeReq.max) - { - newRemainder += sizeReq.size - sizeReq.max; - sizeReq.size = sizeReq.max; - } - else - stillFree.add(sizeReq); + { + SizeRequirements hReq = + new SizeRequirements(child.getMinimumSize().width, + child.getPreferredSize().width, + child.getMaximumSize().width, + child.getAlignmentX()); + hSizeReqs[i] = hReq; + SizeRequirements vReq = + new SizeRequirements(child.getMinimumSize().height, + child.getPreferredSize().height, + child.getMaximumSize().height, + child.getAlignmentY()); + vSizeReqs[i] = vReq; + } } - // recursivly call this method if necessary - if (newRemainder != 0 && stillFree.size() > 0) - distributeSpace(stillFree, newRemainder, dir); } }