001 /*
002 * Copyright (c) Holger Pfaff - http://pfaff.ws
003 *
004 * This software maybe used for any purpose provided the
005 * above copyright notice is retained. It is supplied as is.
006 * No warranty expressed or implied - Use at your own risk.
007 */
008
009 import java.awt.*;
010
011 /**
012 * (#)ColumnLayout.java
013 * @author Holger Pfaff
014 * @version 3.2 19-Mar-2004<br><br>
015 *
016 * Implements a ColumnLayout for gui items which is very useful for forms.
017 * Has the ability to expand specific rows/cols.
018 */
019
020 public class ColumnLayout implements LayoutManager {
021
022 /**
023 * do not expand or no rubbercol/row
024 */
025 public final static int NONE = -1;
026
027 /**
028 * expand horz and vert
029 */
030 public final static int ALL = -2;
031
032 /**
033 * expand horz
034 */
035 public final static int HORZ = -3;
036
037 /**
038 * expand vert
039 */
040 public final static int VERT = -4;
041
042 /**
043 * The border around each cell
044 */
045 protected Insets cellinset;
046
047 /**
048 * North position
049 */
050 public final static int N = 0x1 << 0;
051
052 /**
053 * East position
054 */
055 public final static int E = 0x1 << 1;
056
057 /**
058 * South position
059 */
060 public final static int S = 0x1 << 2;
061
062 /**
063 * West position
064 */
065 public final static int W = 0x1 << 3;
066
067 /**
068 * NorthWest position
069 */
070 public final static int NW = N|W;
071
072 /**
073 * SouthWest position
074 */
075 public final static int SW = S|W;
076
077 /**
078 * NorthEast position
079 */
080 public final static int NE = N|E;
081
082 /**
083 * SouthEast position
084 */
085 public final static int SE = S|E;
086
087 /**
088 * Center position
089 */
090 public final static int CENTER = N|E|S|W;
091
092 /**
093 * where should the component be psoitioned within each cell ?
094 */
095 protected int cellpos; // NW, N, NE, E, SE, S, SW, W, C
096
097 /**
098 * Should we expand each cell to fit exactly (as in GridLayout) ?
099 */
100 protected int cellexpn; // NONE, ALL, HORZ, VERT
101
102 /**
103 * which col to expand if parent larger than preferred size
104 */
105 protected int rubbercolumn; // NONE, ALL or colnumber
106
107 /**
108 * which row to expand if parent larger than preferred size.
109 */
110 protected int rubberrow; // NONE, ALL or rownumber
111
112 /**
113 * no of colums
114 */
115 protected int columns; // no of colums (from constructor)
116
117 /**
118 * Creates a column layout with default insets
119 *
120 * @param columns the number of columns
121 * @param cellexpn expand the component within cell (NONE, ALL, HORZ, VERT)
122 * @param cellpos position of component within cell (NW, N, NE, E, SE, S, SW, W, C)
123 * @param rubbercolumn specify column to expand if parent larger as needed (NONE, ALL, <col>)
124 * @param rubberrow specify row to expand if parent larger as needed (NONE, ALL, <row>)
125 */
126 public ColumnLayout(int columns, int cellexpn, int cellpos, int rubbercolumn, int rubberrow) {
127 this(columns, cellexpn, cellpos, rubbercolumn, rubberrow, new Insets(0,0,0,0));
128 }
129
130 /**
131 * Creates a column layout
132 *
133 * @param columns the number of columns
134 * @param cellexpn expand the component within cell (NONE, ALL, HORZ, VERT)
135 * @param cellpos position of component within cell (NW, N, NE, E, SE, S, SW, W, C)
136 * @param rubbercolumn specify column to expand if parent larger as needed (NONE, ALL, <col>)
137 * @param rubberrow specify row to expand if parent larger as needed (NONE, ALL, <row>)
138 * @param cellinset the border within each cell
139 */
140 public ColumnLayout(int columns, int cellexpn, int cellpos, int rubbercolumn, int rubberrow, Insets cellinset) {
141 this.columns = columns;
142 this.cellexpn = cellexpn;
143 this.cellpos = cellpos;
144 this.rubbercolumn = rubbercolumn;
145 this.rubberrow = rubberrow;
146 this.cellinset = cellinset;
147 }
148
149 /**
150 * calculates the y-pos row r (including cellinset)
151 *
152 * @param rh the rowheight array
153 * @param r the row
154 */
155 private int ry(int[] rh, int r) {
156 int ry = 0;
157 for(int i = 0; i < r; ++i) {
158 ry += rh[i] + cellinset.top + cellinset.bottom;
159 }
160 return ry + cellinset.top;
161 }
162
163 /**
164 * calculates the x-pos for col c (including cellinset)
165 *
166 * @param cw the columnwidth array
167 * @param c the column
168 */
169 private int cx(int[] cw, int c) {
170 int cx = 0;
171 for(int i = 0; i < c; ++i) {
172 cx += cw[i] + cellinset.left + cellinset.right;
173 }
174 return cx + cellinset.left;
175 }
176
177 /**
178 * Get the table size as an int array
179 *
180 * @param c the component array
181 */
182 private int[][] tableSize(Component[] c) {
183 int[][] ts = new int[2][]; // 0=cw 1=th
184
185 ts[0] = new int[columns];
186 ts[1] = new int[(c.length / columns) + (c.length % columns == 0 ? 0 : 1)];
187
188 for(int i = 0; i < c.length; i++) {
189 Dimension d = c[i].getPreferredSize();
190 ts[0][i%columns] = Math.max(d.width, ts[0][i%columns]);
191 ts[1][i/columns] = Math.max(d.height, ts[1][i/columns]);
192 }
193
194 return ts;
195 }
196
197 /**
198 * Position the children. Overridden from LayoutManager
199 *
200 * @param C the parent container
201 */
202 public void layoutContainer(Container C) {
203 Component[] children = C.getComponents();
204 Insets in = C.getInsets();
205 int parentwidth = C.getSize().width - in.left - in.right;
206 int parentheight = C.getSize().height - in.top - in.bottom;
207 int[][] ts = tableSize(children);
208 int[] cw = ts[0];
209 int[] rh = ts[1];
210 Dimension d = preferredLayoutSize(ts, in);
211
212 // rubbercol resizing?
213 if(d.width < parentwidth) {
214 if(rubbercolumn == ALL) {
215 for(int i = 0; i < cw.length; i++) {
216 cw[i] += (parentwidth - d.width) / cw.length;
217 }
218 } else if(rubbercolumn > -1 && rubbercolumn < columns) {
219 cw[rubbercolumn] += parentwidth - d.width;
220 }
221 }
222
223 // rubberrow resizing?
224 if(d.height < parentheight) {
225 if(rubberrow == ALL) {
226 for(int i = 0; i < rh.length; i++) {
227 rh[i] += (parentheight - d.height) / rh.length;
228 }
229 } else if(rubberrow > -1 && rubberrow < rh.length) {
230 rh[rubberrow] += parentheight - d.height;
231 }
232 }
233
234 for(int i = 0; i < children.length; i++) {
235
236 // what row & column ?
237 int r = i / columns;
238 int c = i % columns;
239
240 // top-left pos
241 int x = cx(cw, c) + in.left;
242 int y = ry(rh, r) + in.top;
243
244 // size of this child
245 d = new Dimension(children[i].getPreferredSize());
246
247 // horz/vert resize needed ?
248 switch(cellexpn) {
249 case ALL:
250 case VERT: d.height = rh[r]; if(cellexpn == VERT) break;
251 case HORZ: d.width = cw[c]; break;
252 }
253
254 // horz aligment needed ?
255 if(d.width < cw[c]) {
256 int k = 1;
257 switch(cellpos) {
258 case N:
259 case CENTER:
260 case S: k = 2;
261
262 case NE:
263 case E:
264 case SE: x += (cw[c] - d.width) / k;
265 }
266 }
267
268 // vert aligment needed ?
269 if(d.height < rh[r]) {
270 int k = 1;
271 switch(cellpos) {
272 case E:
273 case CENTER:
274 case W: k = 2;
275
276 case SW:
277 case S:
278 case SE: y += (rh[r] - d.height) / k;
279 }
280 }
281
282 // set pos & size
283 children[i].setBounds(x, y, d.width, d.height);
284 }
285 }
286
287 /**
288 * Calculate the minimum layout size. Same as preferredLayoutSize() for
289 * this layout. Overridden from LayoutManager
290 *
291 * @param C the parent container
292 */
293 public Dimension minimumLayoutSize(Container C) {
294 return preferredLayoutSize(C);
295 }
296
297 /**
298 * Calculate the preferred layout size.
299 *
300 * @param C the parent container
301 */
302 public Dimension preferredLayoutSize(Container C) {
303 return preferredLayoutSize(tableSize(C.getComponents()), C.getInsets());
304 }
305
306 /**
307 * Calculate the preferred layout size.
308 *
309 * @param ts the tablesize array
310 * @param i the insets of the container
311 */
312 private Dimension preferredLayoutSize(int[][] ts, Insets i) {
313 return new Dimension(cx(ts[0], ts[0].length) - cellinset.left + i.left + i.right,
314 ry(ts[1], ts[1].length) - cellinset.top + i.top + i.bottom);
315 }
316
317 /**
318 * Just here to satisfy the interface. Overridden from LayoutManager
319 *
320 * @param c component being removed
321 */
322 public void removeLayoutComponent(Component c) {}
323
324 /**
325 * Just here to satisfy the interface. Overridden from LayoutManager
326 *
327 * @param s additional layout info
328 * @param c component being added
329 */
330 public void addLayoutComponent(String s, Component c) {}
331 }