001package jmri.util.javaworld;
002
003import java.awt.Component;
004import java.awt.Container;
005import java.awt.Dimension;
006import java.awt.GridLayout;
007import java.awt.Insets;
008
009/**
010 * Grid Layout which allows components of different sizes.
011 * From http://www.javaworld.com/javaworld/javatips/javatip121/GridLayout2.java
012 * Javaworld article by Bogdan Dorohonceanu.
013 */
014public class GridLayout2 extends GridLayout {
015
016    public GridLayout2() {
017        this(1, 0, 0, 0);
018    }
019
020    public GridLayout2(int rows, int cols) {
021        this(rows, cols, 0, 0);
022    }
023
024    public GridLayout2(int rows, int cols, int hgap, int vgap) {
025        super(rows, cols, hgap, vgap);
026    }
027
028    @Override
029    public Dimension preferredLayoutSize(Container parent) {
030        synchronized (parent.getTreeLock()) {
031            Insets insets = parent.getInsets();
032            int ncomponents = parent.getComponentCount();
033            int nrows = getRows();
034            int ncols = getColumns();
035            if (nrows > 0) {
036                ncols = (ncomponents + nrows - 1) / nrows;
037            } else {
038                nrows = (ncomponents + ncols - 1) / ncols;
039            }
040            int[] w = new int[ncols];
041            int[] h = new int[nrows];
042            for (int i = 0; i < ncomponents; i++) {
043                int r = i / ncols;
044                int c = i % ncols;
045                Component comp = parent.getComponent(i);
046                Dimension d = comp.getPreferredSize();
047                if (w[c] < d.width) {
048                    w[c] = d.width;
049                }
050                if (h[r] < d.height) {
051                    h[r] = d.height;
052                }
053            }
054            int nw = 0;
055            for (int j = 0; j < ncols; j++) {
056                nw += w[j];
057            }
058            int nh = 0;
059            for (int i = 0; i < nrows; i++) {
060                nh += h[i];
061            }
062            return new Dimension(insets.left + insets.right + nw + (ncols - 1) * getHgap(),
063                    insets.top + insets.bottom + nh + (nrows - 1) * getVgap());
064        }
065    }
066
067    @Override
068    public Dimension minimumLayoutSize(Container parent) {
069        synchronized (parent.getTreeLock()) {
070            Insets insets = parent.getInsets();
071            int ncomponents = parent.getComponentCount();
072            int nrows = getRows();
073            int ncols = getColumns();
074            if (nrows > 0) {
075                ncols = (ncomponents + nrows - 1) / nrows;
076            } else {
077                nrows = (ncomponents + ncols - 1) / ncols;
078            }
079            int[] w = new int[ncols];
080            int[] h = new int[nrows];
081            for (int i = 0; i < ncomponents; i++) {
082                int r = i / ncols;
083                int c = i % ncols;
084                Component comp = parent.getComponent(i);
085                Dimension d = comp.getMinimumSize();
086                if (w[c] < d.width) {
087                    w[c] = d.width;
088                }
089                if (h[r] < d.height) {
090                    h[r] = d.height;
091                }
092            }
093            int nw = 0;
094            for (int j = 0; j < ncols; j++) {
095                nw += w[j];
096            }
097            int nh = 0;
098            for (int i = 0; i < nrows; i++) {
099                nh += h[i];
100            }
101            return new Dimension(insets.left + insets.right + nw + (ncols - 1) * getHgap(),
102                    insets.top + insets.bottom + nh + (nrows - 1) * getVgap());
103        }
104    }
105
106    @Override
107    public void layoutContainer(Container parent) {
108        synchronized (parent.getTreeLock()) {
109            Insets insets = parent.getInsets();
110            int ncomponents = parent.getComponentCount();
111            int nrows = getRows();
112            int ncols = getColumns();
113            if (ncomponents == 0) {
114                return;
115            }
116            if (nrows > 0) {
117                ncols = (ncomponents + nrows - 1) / nrows;
118            } else {
119                nrows = (ncomponents + ncols - 1) / ncols;
120            }
121            int hgap = getHgap();
122            int vgap = getVgap();
123            // scaling factors      
124            Dimension pd = preferredLayoutSize(parent);
125            double sw = (1.0 * parent.getWidth()) / pd.width;
126            double sh = (1.0 * parent.getHeight()) / pd.height;
127            // scale
128            int[] w = new int[ncols];
129            int[] h = new int[nrows];
130            for (int i = 0; i < ncomponents; i++) {
131                int r = i / ncols;
132                int c = i % ncols;
133                Component comp = parent.getComponent(i);
134                Dimension d = comp.getPreferredSize();
135                d.width = (int) (sw * d.width);
136                d.height = (int) (sh * d.height);
137                if (w[c] < d.width) {
138                    w[c] = d.width;
139                }
140                if (h[r] < d.height) {
141                    h[r] = d.height;
142                }
143            }
144            for (int c = 0, x = insets.left; c < ncols; c++) {
145                for (int r = 0, y = insets.top; r < nrows; r++) {
146                    int i = r * ncols + c;
147                    if (i < ncomponents) {
148                        parent.getComponent(i).setBounds(x, y, w[c], h[r]);
149                    }
150                    y += h[r] + vgap;
151                }
152                x += w[c] + hgap;
153            }
154        }
155    }
156}