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 }