1 /* 2 Copyright aswing.org, see the LICENCE.txt. 3 */ 4 5 import org.aswing.*; 6 import org.aswing.geom.*; 7 8 /** 9 * A flow layout arranges components in a left-to-right flow, much 10 * like lines of text in a paragraph. Flow layouts are typically used 11 * to arrange buttons in a panel. It will arrange 12 * buttons left to right until no more buttons fit on the same line. 13 * Each line is centered. 14 * <p> 15 * For example, the following picture shows an applet using the flow 16 * layout manager (its default layout manager) to position three buttons: 17 * <p> 18 * A flow layout lets each component assume its natural (preferred) size. 19 * 20 * @author iiley 21 */ 22 class org.aswing.FlowLayout extends EmptyLayout{ 23 24 /** 25 * This value indicates that each row of components 26 * should be left-justified. 27 */ 28 public static var LEFT:Number = 0; 29 30 /** 31 * This value indicates that each row of components 32 * should be centered. 33 */ 34 public static var CENTER:Number = 1; 35 36 /** 37 * This value indicates that each row of components 38 * should be right-justified. 39 */ 40 public static var RIGHT:Number = 2; 41 42 /** 43 * <code>align</code> is the property that determines 44 * how each row distributes empty space. 45 * It can be one of the following values: 46 * <ul> 47 * <code>LEFT</code> 48 * <code>RIGHT</code> 49 * <code>CENTER</code> 50 * </ul> 51 * 52 * @see #getAlignment 53 * @see #setAlignment 54 */ 55 private var align:Number; 56 57 /** 58 * The flow layout manager allows a seperation of 59 * components with gaps. The horizontal gap will 60 * specify the space between components. 61 * 62 * @see #getHgap() 63 * @see #setHgap(int) 64 */ 65 private var hgap:Number; 66 67 /** 68 * The flow layout manager allows a seperation of 69 * components with gaps. The vertical gap will 70 * specify the space between rows. 71 * 72 * @see #getHgap() 73 * @see #setHgap(int) 74 */ 75 private var vgap:Number; 76 77 /** 78 * Creates a new flow layout manager with the indicated alignment 79 * and the indicated horizontal and vertical gaps. 80 * <p> 81 * The value of the alignment argument must be one of 82 * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>, 83 * or <code>FlowLayout.CENTER</code>. 84 * @param align the alignment value, default is LEFT 85 * @param hgap the horizontal gap between components, default 5 86 * @param vgap the vertical gap between components, default 5 87 */ 88 public function FlowLayout(align:Number, hgap:Number, vgap:Number) { 89 if(align == undefined) align = LEFT; 90 if(hgap == undefined) hgap = 5; 91 if(vgap == undefined) vgap = 5; 92 this.hgap = hgap; 93 this.vgap = vgap; 94 setAlignment(align); 95 } 96 97 /** 98 * Gets the alignment for this layout. 99 * Possible values are <code>FlowLayout.LEFT</code>, 100 * <code>FlowLayout.RIGHT</code>, <code>FlowLayout.CENTER</code>, 101 * @return the alignment value for this layout 102 * @see #setAlignment 103 */ 104 public function getAlignment():Number { 105 return align; 106 } 107 108 /** 109 * Sets the alignment for this layout. 110 * Possible values are 111 * <ul> 112 * <li><code>FlowLayout.LEFT</code> 113 * <li><code>FlowLayout.RIGHT</code> 114 * <li><code>FlowLayout.CENTER</code> 115 * </ul> 116 * @param align one of the alignment values shown above 117 * @see #getAlignment() 118 */ 119 public function setAlignment(align:Number):Void { 120 //Flashout.log("set align : " + align) 121 this.align = align; 122 } 123 124 /** 125 * Gets the horizontal gap between components. 126 * @return the horizontal gap between components 127 * @see #setHgap() 128 */ 129 public function getHgap():Number { 130 return hgap; 131 } 132 133 /** 134 * Sets the horizontal gap between components. 135 * @param hgap the horizontal gap between components 136 * @see #getHgap() 137 */ 138 public function setHgap(hgap:Number):Void { 139 this.hgap = hgap; 140 } 141 142 /** 143 * Gets the vertical gap between components. 144 * @return the vertical gap between components 145 * @see #setVgap() 146 */ 147 public function getVgap():Number { 148 return vgap; 149 } 150 151 /** 152 * Sets the vertical gap between components. 153 * @param vgap the vertical gap between components 154 * @see #getVgap() 155 */ 156 public function setVgap(vgap:Number):Void { 157 this.vgap = vgap; 158 } 159 160 /** 161 * Returns the preferred dimensions for this layout given the 162 * <i>visible</i> components in the specified target container. 163 * @param target the component which needs to be laid out 164 * @return the preferred dimensions to lay out the 165 * subcomponents of the specified container 166 * @see Container 167 * @see #doLayout() 168 */ 169 public function preferredLayoutSize(target:Container):Dimension { 170 var dim:Dimension = new Dimension(0, 0); 171 var nmembers:Number = target.getComponentCount(); 172 173 var counted:Number = 0; 174 for (var i:Number = 0 ; i < nmembers ; i++) { 175 var m:Component = target.getComponent(i); 176 if (m.isVisible()) { 177 var d:Dimension = m.getPreferredSize(); 178 dim.height = Math.max(dim.height, d.height); 179 if (counted > 0) { 180 dim.width += hgap; 181 } 182 dim.width += d.width; 183 counted ++; 184 } 185 } 186 var insets:Insets = target.getInsets(); 187 dim.width += insets.left + insets.right + hgap*2; 188 dim.height += insets.top + insets.bottom + vgap*2; 189 return dim; 190 } 191 192 /** 193 * Returns the minimum dimensions needed to layout the <i>visible</i> 194 * components contained in the specified target container. 195 * @param target the component which needs to be laid out 196 * @return the minimum dimensions to lay out the 197 * subcomponents of the specified container 198 * @see #preferredLayoutSize() 199 * @see Container 200 * @see Container#doLayout() 201 */ 202 public function minimumLayoutSize(target:Container):Dimension { 203 var dim:Dimension = new Dimension(0, 0); 204 var nmembers:Number = target.getComponentCount(); 205 var counted:Number = 0; 206 for (var i:Number = 0 ; i < nmembers ; i++) { 207 var m:Component = target.getComponent(i); 208 if (m.isVisible()) { 209 var d:Dimension = m.getMinimumSize(); 210 dim.height = Math.max(dim.height, d.height); 211 if (counted > 0) { 212 dim.width += hgap; 213 } 214 dim.width += d.width; 215 counted ++; 216 } 217 } 218 var insets:Insets = target.getInsets(); 219 dim.width += insets.left + insets.right + hgap*2; 220 dim.height += insets.top + insets.bottom + vgap*2; 221 return dim; 222 } 223 224 /** 225 * Centers the elements in the specified row, if there is any slack. 226 * @param target the component which needs to be moved 227 * @param x the x coordinate 228 * @param y the y coordinate 229 * @param width the width dimensions 230 * @param height the height dimensions 231 * @param rowStart the beginning of the row 232 * @param rowEnd the the ending of the row 233 */ 234 private function moveComponents(target:Container, x:Number, y:Number, width:Number, height:Number, 235 rowStart:Number, rowEnd:Number, ltr:Boolean):Void { 236 switch (align) { 237 case LEFT: 238 x += ltr ? 0 : width; 239 break; 240 case CENTER: 241 x += width / 2; 242 break; 243 case RIGHT: 244 x += ltr ? width : 0; 245 break; 246 } 247 for (var i:Number = rowStart ; i < rowEnd ; i++) { 248 var m:Component = target.getComponent(i); 249 var d:Dimension = m.getSize(); 250 var td:Dimension = target.getSize(); 251 if (m.isVisible()) { 252 if (ltr) { 253 m.setLocation(x, y + (height - d.height) / 2); 254 } else { 255 m.setLocation(td.width - x - d.width, y + (height - d.height) / 2); 256 } 257 x += d.width + hgap; 258 } 259 } 260 } 261 262 /** 263 * Lays out the container. This method lets each component take 264 * its preferred size by reshaping the components in the 265 * target container in order to satisfy the alignment of 266 * this <code>FlowLayout</code> object. 267 * @param target the specified component being laid out 268 * @see Container 269 * @see Container#doLayout 270 */ 271 public function layoutContainer(target:Container):Void { 272 var insets:Insets = target.getInsets(); 273 var td:Dimension = target.getSize(); 274 var maxwidth:Number = td.width - (insets.left + insets.right + hgap*2); 275 var nmembers:Number = target.getComponentCount(); 276 var x:Number = 0; 277 var y:Number = insets.top + vgap; 278 var rowh:Number = 0; 279 var start:Number = 0; 280 281 var ltr:Boolean = true; 282 283 for (var i:Number = 0 ; i < nmembers ; i++) { 284 var m:Component = target.getComponent(i); 285 if (m.isVisible()) { 286 var d:Dimension = m.getPreferredSize(); 287 m.setSize(d.width, d.height); 288 289 if ((x == 0) || ((x + d.width) <= maxwidth)) { 290 if (x > 0) { 291 x += hgap; 292 } 293 x += d.width; 294 rowh = Math.max(rowh, d.height); 295 } else { 296 moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i, ltr); 297 x = d.width; 298 y += vgap + rowh; 299 rowh = d.height; 300 start = i; 301 } 302 } 303 } 304 moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers, ltr); 305 } 306 307 /** 308 * Returns a string representation of this <code>FlowLayout</code> 309 * object and its values. 310 * @return a string representation of this layout 311 */ 312 public function toString():String { 313 var str:String = ""; 314 switch (align) { 315 case LEFT: str = ",align=left"; break; 316 case CENTER: str = ",align=center"; break; 317 case RIGHT: str = ",align=right"; break; 318 } 319 return "FlowLayout[hgap=" + hgap + ",vgap=" + vgap + str + "]"; 320 } 321 } 322