Mega Code Archive

 
Categories / Java / Swing JFC
 

Tile Layout

import java.awt.*; import java.util.LinkedList; import java.io.Serializable; /*  * Relative Component Layout Manager  * Copyright (c) 1999 John Catherino  * The cajo project: https://cajo.dev.java.net  *  * For issues or suggestions mailto:cajo@dev.java.net  *  * This library is free software; you can redistribute it and/or modify  * it under the terms of the GNU Lesser General Public License, at version  * 2.1 of the licence, or any later version published by the Free Software  * Foundation.  *  * This program 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 Lesser General Public License for more details.  *  * You can receive a copy of the GNU Lesser General Public License from their  * website, http://fsf.org/licenses/lgpl.html; or via snail mail, Free  * Software Foundation Inc., 51 Franklin Street, Boston MA 02111-1301, USA  */ /**  * A rather unique LayoutManager. In addition to laying out components relative  * to the container, it also supports layout relative to components <i>within</i>  * the container. Its purpose is to support arbitrarily complex component  * layouts, of an unlimited number of components, within a single container. It  * can easily create complex layouts that would otherwise require many  * subpanels, and multiple standard layout managers. It also can create layouts  * that are completely <i>impossible</i>, with standard layout managers. These  * features make this layout manager extremely flexible, and makes  * advancedlayouts extremely fast. It just may be, the last and only  * LayoutManager you'll ever need.  * <p>  *   * Components can be laid out above, below, left, or right of either a  * referenced component in the panel, or to the panel itself. Its width and  * height can be specified with similar flexibility. Absolute and proportional  * bounds are also supported. In typical use, one or more <i>'reference'</i>  * tiles are laid, and the rest of the components are set relative to them.  * <p>  *   * Usage example:<blockquote><tt><pre>  * panel.add(new JLabel(&quot;Label text:&quot;), new Object[]{  *       new Integer(TileLayout.LEFTINDENT + TileLayout.NOOFFSET +  *       TileLayout.PROPWIDTH + TileLayout.FULLHEIGHT), refComponent,  *       new Insets(-5, 10, 5, 10), new Rectangle(0, 0, 333, 0)  * // proportion rectangle 33.3%w  *       });  * </tt></pre>  *   * </blockquote>  * <p>  *   * Up to four alignment constraints can be specified, their order does not  * matter:  *   * <p>  * <ul>  * <li> Positioning constants for indent, offset, width, and height  * <li> A Component for placement relative to, otherwise the container  * <li> A Rectangle for fixed and proportional component bounds  * <li> Insets to trim the resulting component boundaries  * </ul>  * <p>  *   * <u><i>Note</u>:</i> since the JRE <i>draws</i> components from last added  * to first; the manager lays them out similarly. Therefore, in order to layout  * relative to another component, the reference component must be added <u>after</u>  * the dependent one. I know this can be a drag at first, but it becomes  * critically important when components are laid out on top of others, or  * overlapping. This is a <i>super cool</i> capability of this layout manager.  *   * @version 1.0, 01-Nov-99 Initial release  * @author John Catherino  */ public final class TileLayout implements LayoutManager2, Serializable {    private static final long serialVersionUID = 1L;    private static final Dimension NONE  = new Dimension();    private final LinkedList components  = new LinkedList();    private final LinkedList constraints = new LinkedList();    private void align(Dimension cont, Object cons[], Component comp) {       int align = 0;       Insets insets = null;       Rectangle tile = null, fixd = null;       if (cons != null) {          for (int i = 0; i < cons.length; i++) { // gather constraints             if (cons[i] != null) {                if (cons[i] instanceof Rectangle) fixd = (Rectangle)cons[i];                else if (cons[i] instanceof Insets) insets = (Insets)cons[i];                else if (cons[i] instanceof Integer) align = ((Integer)cons[i]).intValue();                else if (cons[i] instanceof Component) tile = ((Component)cons[i]).getBounds();             }          }       }       if (tile == null) tile = new Rectangle(cont);       Rectangle pref = new Rectangle(tile.getLocation(), comp.getPreferredSize());       // perform component positioning:       if ((align & 0x004000) != 0) pref.width = fixd.width;       else if ((align & 0x008000) != 0) pref.width = (tile.width * fixd.width + 500) / 1000;       else if ((align & 0x010000) != 0) pref.width = tile.width;       if ((align & 0x080000) != 0) pref.height = fixd.height;       else if ((align & 0x100000) != 0) pref.height = (tile.height             * fixd.height + 500) / 1000;       else if ((align & 0x200000) != 0) pref.height = tile.height;       if ((align & 0x000001) != 0) pref.x -= pref.width;       else if ((align & 0x000002) != 0) pref.x += (tile.width - pref.width >> 1);       else if ((align & 0x000004) != 0) pref.x += tile.width - pref.width;       else if ((align & 0x000008) != 0) pref.x += tile.width;       else if ((align & 0x000010) != 0) pref.x += fixd.x;       else if ((align & 0x000020) != 0) pref.x += (tile.width * fixd.x + 500) / 1000;       if ((align & 0x000040) != 0) pref.y -= pref.height;       else if ((align & 0x000080) != 0) pref.y += (tile.height - pref.height >> 1);       else if ((align & 0x000100) != 0) pref.y += tile.height - pref.height;       else if ((align & 0x000200) != 0) pref.y += tile.height;       else if ((align & 0x000400) != 0) pref.y += fixd.y;       else if ((align & 0x000800) != 0) pref.y += (tile.height * fixd.y + 500) / 1000;       if ((align & 0x001000) != 0) pref.setBounds(0, pref.y, pref.x             + pref.width, pref.height);       else if ((align & 0x002000) != 0) pref.width = cont.width - pref.x;       if ((align & 0x020000) != 0) pref.setBounds(pref.x, 0, pref.width, pref.y             + pref.height);       else if ((align & 0x040000) != 0) pref.height = cont.height - pref.y;       if (insets != null) { // apply insets, if any:          pref.x += insets.left;          pref.y += insets.top;          pref.width -= insets.left + insets.right;          pref.height -= insets.top + insets.bottom;       }       // Note: this can cause surprising results, so use it, if you dare. :-)       // Honour component minimum size:       Dimension d = comp.getMinimumSize();       if (pref.width < d.width) pref.width = d.width;       if (pref.height < d.height) pref.height = d.height;       comp.setBounds(pref); // now the tile is set!    }    /**     * This constant specifies placement of the component even with the left     * border of the provided reference component, otherwise to the container     * itself.     */    public static final int NOINDENT = 0x000000;    /**     * This constant specifies placement of the component with its right border     * one pixel to the left of the provided reference component, otherwise to     * the container itself.     */    public static final int LEFTINDENT = 0x000001;    /**     * This constant specifies placement of the component evenly between the left     * and right borders of the provided reference component, otherwise to the     * container itself.     */    public static final int CENTERINDENT = 0x000002;    /**     * This constant specifies placement of the component with its right border     * evenly aligned with the right border of the provided reference component,     * otherwise to the container itself.     */    public static final int FULLINDENT = 0x000004;    /**     * This constant specifies placement of the left border of the component one     * pixel to the right of the provided reference component origin, otherwise     * to the container itself.     */    public static final int RIGHTINDENT = 0x000008;    /**     * Used in conjunction with a Rectangle constraint, the x value represents     * the desired component indent as a fixed number of pixels right of the     * provided component origin, otherwise to the container itself.     */    public static final int FIXEDINDENT = 0x000010;    /**     * Used in conjunction with a Rectangle constraint, the x value represents     * the desired component indent as a percentage (2000 = 200.0%) of a provided     * component, otherwise to the container itself.     */    public static final int PROPINDENT = 0x000020;    /**     * This constant specifies placement of the component even with the top     * border of the provided reference component, otherwise to the container     * itself.     */    public static final int NOOFFSET = 0x000000;    /**     * This constant specifies placement of the component with its bottom border     * one pixel above the provided reference component, otherwise to the     * container itself.     */    public static final int TOPOFFSET = 0x000040;    /**     * This constant specifies placement of the component evenly between the top     * and bottom borders of the provided reference component, otherwise to the     * container itself.     */    public static final int CENTEROFFSET = 0x000080;    /**     * This constant specifies placement of the component with its bottom border     * evenly aligned with the bottom border of the provided reference component,     * otherwise to the container itself.     */    public static final int FULLOFFSET = 0x000100;    /**     * This constant specifies placement of the top border of the component one     * pixel below the provided reference component origin, otherwise to the     * container itself.     */    public static final int BOTTOMOFFSET = 0x000200;    /**     * Used in conjunction with a Rectangle constraint, the y value represents     * the desired component offset as a fixed number of pixels below the     * provided component origin, otherwise to the container itself.     */    public static final int FIXEDOFFSET = 0x000400;    /**     * Used in conjunction with a Rectangle constraint, the y value represents     * the desired component offset as a percentage (2000 = 200.0%) of a provided     * component, otherwise to the container itself.     */    public static final int PROPOFFSET = 0x000800;    /**     * This constant specifies that the component have its preferred width, as     * returned by its getPreferredSize method.     */    public static final int PREFWIDTH = 0x000000;    /**     * This constant specifies that the component be made wide enough such that     * given its computed right margin, its left margin will align with that of     * its container.     */    public static final int CLAMPLEFT = 0x001000;    /**     * This constant specifies that the component be made wide enough such that     * given its computed origin, its right margin will align with that of its     * container.     */    public static final int CLAMPRIGHT = 0x002000;    /**     * Used in conjunction with a Rectangle constraint, the width value     * represents the desired component width as a fixed number of pixels.     */    public static final int FIXEDWIDTH = 0x004000;    /**     * Used in conjunction with a Rectangle constraint, the width value     * represents the desired component offset as a percentage (2000 = 200.0%) of     * a provided component, otherwise to the container itself.     */    public static final int PROPWIDTH = 0x008000;    /**     * This constant specifies that the component be made exactly as wide as its     * reference component, otherwise as the container itself.     */    public static final int FULLWIDTH = 0x010000;    /**     * This constant specifies that the component have its preferred height, as     * returned by its getPreferredSize method.     */    public static final int PREFHEIGHT = 0x000000;    /**     * This constant specifies that the component be made high enough such that     * given its computed bottom margin, its top margin will align with that of     * its container.     */    public static final int CLAMPTOP = 0x020000;    /**     * This constant specifies that the component be made high enough such that     * given its computed origin, its bottom margin will align with that of its     * container.     */    public static final int CLAMPBOTTOM = 0x040000;    /**     * Used in conjunction with a Rectangle constraint, the height value     * represents the desired component width as a fixed number of pixels.     */    public static final int FIXEDHEIGHT = 0x080000;    /**     * Used in conjunction with a Rectangle constraint, the height value     * represents the desired component offset as a percentage (2000 = 200.0%) of     * a provided component, otherwise to the container itself.     */    public static final int PROPHEIGHT = 0x100000;    /**     * This constant specifies that the component be made exactly as high as its     * reference component, otherwise as the container itself.     */    public static final int FULLHEIGHT = 0x200000;    /**     * A frequently used position, used in conjunction with a reference     * component, it will locate the component directly over, with the same width     * and height.     */    public static final Integer ABOVE = new Integer(NOINDENT + TOPOFFSET          + FULLWIDTH + FULLHEIGHT);    /**     * A frequently used position, used in conjunction with a reference     * component, it will locate the component directly beneath, with the same     * width and height.     */    public static final Integer BELOW = new Integer(NOINDENT + BOTTOMOFFSET          + FULLWIDTH + FULLHEIGHT);    /**     * A frequently used position, used in conjunction with a reference     * component, it will locate the component directly adjacent, to its right,     * with the same width and height.     */    public static final Integer RIGHT = new Integer(RIGHTINDENT + NOOFFSET          + FULLWIDTH + FULLHEIGHT);    /**     * A frequently used position, used in conjunction with a reference     * component, it will locate the component directly adjacent, to its left,     * with the same width and height.     */    public static final Integer LEFT = new Integer(LEFTINDENT + NOOFFSET          + FULLWIDTH + FULLHEIGHT);    /**     * A frequently used position, it will render the component using the exact     * size of the reference component, or container.     */    public static final Integer FULLSIZE = new Integer(NOINDENT + NOOFFSET          + FULLWIDTH + FULLHEIGHT);    /**     * Nothing is performed in the constructor, it is bodyless.     */    public TileLayout() {}    /**     * The primary component addition method. Components are added for layout,     * and its constraints are provided as an Object array. Up to 4 constraints     * may be specified, and their order is not important. The following are the     * applicable constraints:     * <ul>     * <p>     * <li> Rectangle for fixed or proportional component bounds     * <li> Insets to trim the final boundaries after computation     * <li> Integer of TileLayout positioning constants     * <li> Component for relative placement, instead of container     * </ul>     *      * @param comp The component to be laid out within the container.     * @param cons An Object[] containing 1 or more constraints.     */    public void addLayoutComponent(Component comp, Object cons) {       components.add(comp);       constraints.add(cons);    }    /**     * This method will make the added component exactly the same size as the     * container itself. It is useful for adding wallpaper.     *      * @param comp The component to fill the container.     * @param name The name of the component, unused by TileLayout.     */    public void addLayoutComponent(String name, Component comp) {       components.add(comp);       constraints.add(new Object[]{ FULLSIZE });    }    /**     * As expected, removes the component from the ordered layout list.     */    public void removeLayoutComponent(Component comp) {       for (int i = 0; i < components.size(); i++) {          if (components.get(i) == comp) {             components.remove(i);             constraints.remove(i);             return;          }       }       throw new IllegalArgumentException("Component not in container");    }    /**     * Lays out the components, last added to first added, according to their     * specified constraints.     */    public void layoutContainer(Container parent) {       Dimension container = parent.getSize();       for (int i = components.size() - 1; i >= 0; i--)          align(container, (Object[])constraints.get(i),             (Component)components.get(i));    }    /**     * Bodyless implementation, as TileLayout uses no cached information.     */    public void invalidateLayout(Container target) {}    /**     * Indicate center alignment.     */    public float getLayoutAlignmentX(Container target) { return 0.5F; }    /**     * Indicate center alignment.     */    public float getLayoutAlignmentY(Container target) { return 0.5F; }    /**     * Indicates no minimum size.     */    public Dimension minimumLayoutSize(Container parent) { return NONE; }    /**     * Indicates no maximum size.     */    public Dimension maximumLayoutSize(Container parent) { return NONE; }    /**     * Indicates no preferred size.     */    public Dimension preferredLayoutSize(Container parent) { return NONE; } }