View Javadoc

1   /*
2    * Created on Nov 16, 2004 
3    * Original filename was FlowLayout2Center.java
4    * 
5    *   Magic-Project is a turn based strategy simulator
6    *   Copyright (C) 2003-2007 Fabrice Daugan
7    *
8    *   This program is free software; you can redistribute it and/or modify it 
9    * under the terms of the GNU General Public License as published by the Free 
10   * Software Foundation; either version 2 of the License, or (at your option) any
11   * later version.
12   *
13   *   This program is distributed in the hope that it will be useful, but WITHOUT 
14   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
16   * details.
17   *
18   *   You should have received a copy of the GNU General Public License along  
19   * with this program; if not, write to the Free Software Foundation, Inc., 
20   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21   * 
22   */
23  package net.sf.magicproject.ui.layout;
24  
25  import java.awt.Component;
26  import java.awt.Container;
27  import java.awt.Dimension;
28  import java.awt.Insets;
29  import java.awt.LayoutManager;
30  
31  /***
32   * A flow layout arranges components in a directional flow, much like lines of
33   * text in a paragraph. The flow direction is determined by the container's
34   * <code>componentOrientation</code> property and may be one of two values:
35   * <ul>
36   * <li><code>ComponentOrientation.LEFT_TO_RIGHT</code>
37   * <li><code>ComponentOrientation.RIGHT_TO_LEFT</code>
38   * </ul>
39   * Flow layouts are typically used to arrange buttons in a panel. It arranges
40   * buttons horizontally until no more buttons fit on the same line.
41   * <p>
42   * A flow layout lets each component assume its natural (preferred) size.
43   * 
44   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
45   * @since 0.80
46   */
47  public class FlowLayout2Center implements LayoutManager {
48  
49  	/***
50  	 * Constructs a new <code>FlowLayout2Center</code> with a centered alignment
51  	 * and a default 5-unit horizontal and vertical gap.
52  	 */
53  	public FlowLayout2Center() {
54  		this(5, 5);
55  	}
56  
57  	/***
58  	 * Creates a new flow layout manager with the indicated horizontal and
59  	 * vertical gaps.
60  	 * <p>
61  	 * 
62  	 * @param hgap
63  	 *          the horizontal gap between components and between the components
64  	 *          and the borders of the <code>Container</code>
65  	 * @param vgap
66  	 *          the vertical gap between components and between the components and
67  	 *          the borders of the <code>Container</code>
68  	 */
69  	public FlowLayout2Center(int hgap, int vgap) {
70  		this.hgap = hgap;
71  		this.vgap = vgap;
72  	}
73  
74  	/***
75  	 * Gets the horizontal gap between components and between the components and
76  	 * the borders of the <code>Container</code>
77  	 * 
78  	 * @return the horizontal gap between components and between the components
79  	 *         and the borders of the <code>Container</code>
80  	 * @see java.awt.FlowLayout#setHgap
81  	 * @since JDK1.1
82  	 */
83  	public int getHgap() {
84  		return hgap;
85  	}
86  
87  	/***
88  	 * Sets the horizontal gap between components and between the components and
89  	 * the borders of the <code>Container</code>.
90  	 * 
91  	 * @param hgap
92  	 *          the horizontal gap between components and between the components
93  	 *          and the borders of the <code>Container</code>
94  	 * @see java.awt.FlowLayout#getHgap
95  	 * @since JDK1.1
96  	 */
97  	public void setHgap(int hgap) {
98  		this.hgap = hgap;
99  	}
100 
101 	/***
102 	 * Gets the vertical gap between components and between the components and the
103 	 * borders of the <code>Container</code>.
104 	 * 
105 	 * @return the vertical gap between components and between the components and
106 	 *         the borders of the <code>Container</code>
107 	 * @see java.awt.FlowLayout#setVgap
108 	 * @since JDK1.1
109 	 */
110 	public int getVgap() {
111 		return vgap;
112 	}
113 
114 	/***
115 	 * Sets the vertical gap between components and between the components and the
116 	 * borders of the <code>Container</code>.
117 	 * 
118 	 * @param vgap
119 	 *          the vertical gap between components and between the components and
120 	 *          the borders of the <code>Container</code>
121 	 * @see java.awt.FlowLayout#getVgap
122 	 * @since JDK1.1
123 	 */
124 	public void setVgap(int vgap) {
125 		this.vgap = vgap;
126 	}
127 
128 	public void addLayoutComponent(String name, Component comp) {
129 		// Ignore this event
130 	}
131 
132 	public void removeLayoutComponent(Component comp) {
133 		// Ignore this event
134 	}
135 
136 	public Dimension preferredLayoutSize(Container target) {
137 		synchronized (target.getTreeLock()) {
138 			Dimension dim = new Dimension(0, 0);
139 			int nmembers = target.getComponentCount();
140 			boolean firstVisibleComponent = true;
141 
142 			for (int i = 0; i < nmembers; i++) {
143 				Component m = target.getComponent(i);
144 				if (m.isVisible()) {
145 					Dimension d = m.getPreferredSize();
146 					dim.height = Math.max(dim.height, d.height);
147 					if (firstVisibleComponent) {
148 						firstVisibleComponent = false;
149 					} else {
150 						dim.width += hgap;
151 					}
152 					dim.width += d.width;
153 				}
154 			}
155 			Insets insets = target.getInsets();
156 			dim.width += insets.left + insets.right + hgap * 2;
157 			dim.height += insets.top + insets.bottom + vgap * 2;
158 			return dim;
159 		}
160 	}
161 
162 	public Dimension minimumLayoutSize(Container target) {
163 		synchronized (target.getTreeLock()) {
164 			Dimension dim = new Dimension(0, 0);
165 			int nmembers = target.getComponentCount();
166 
167 			for (int i = 0; i < nmembers; i++) {
168 				Component m = target.getComponent(i);
169 				if (m.isVisible()) {
170 					Dimension d = m.getMinimumSize();
171 					dim.height = Math.max(dim.height, d.height);
172 					if (i > 0) {
173 						dim.width += hgap;
174 					}
175 					dim.width += d.width;
176 				}
177 			}
178 			Insets insets = target.getInsets();
179 			dim.width += insets.left + insets.right + hgap * 2;
180 			dim.height += insets.top + insets.bottom + vgap * 2;
181 			return dim;
182 		}
183 	}
184 
185 	public void layoutContainer(Container target) {
186 		synchronized (target.getTreeLock()) {
187 			Insets insets = target.getInsets();
188 			int maxwidth = target.getWidth()
189 					- (insets.left + insets.right + hgap * 2);
190 			int nmembers = target.getComponentCount();
191 			int x = 0;
192 			int y = target.getHeight() - insets.bottom - vgap;
193 			int rowh = 0;
194 			int start = 0;
195 
196 			for (int i = 0; i < nmembers; i++) {
197 				Component m = target.getComponent(i);
198 				if (m.isVisible()) {
199 					Dimension d = m.getPreferredSize();
200 					m.setSize(d.width, d.height);
201 
202 					if (x == 0 || x + d.width <= maxwidth) {
203 						if (x > 0) {
204 							x += hgap;
205 						}
206 						x += d.width;
207 						rowh = Math.max(rowh, d.height);
208 					} else {
209 						moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh,
210 								start, i);
211 						x = d.width;
212 						y -= vgap + rowh;
213 						rowh = d.height;
214 						start = i;
215 					}
216 				}
217 			}
218 			moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start,
219 					nmembers);
220 		}
221 	}
222 
223 	/***
224 	 * Centers the elements in the specified row, if there is any slack.
225 	 * 
226 	 * @param target
227 	 *          the component which needs to be moved
228 	 * @param x
229 	 *          the x coordinate
230 	 * @param y
231 	 *          the y coordinate
232 	 * @param width
233 	 *          the width dimensions
234 	 * @param height
235 	 *          the height dimensions
236 	 * @param rowStart
237 	 *          the beginning of the row
238 	 * @param rowEnd
239 	 *          the the ending of the row
240 	 */
241 	private void moveComponents(Container target, int x, int y, int width,
242 			int height, int rowStart, int rowEnd) {
243 		int xRec = x;
244 		synchronized (target.getTreeLock()) {
245 			xRec += width / 2;
246 			for (int i = rowStart; i < rowEnd; i++) {
247 				Component m = target.getComponent(i);
248 				if (m.isVisible()) {
249 					m.setLocation(target.getWidth() - xRec - m.getWidth(), y - height
250 							+ (height - m.getHeight()) / 2);
251 					xRec += m.getWidth() + hgap;
252 				}
253 			}
254 		}
255 	}
256 
257 	/***
258 	 * The flow layout manager allows a seperation of components with gaps. The
259 	 * horizontal gap will specify the space between components and between the
260 	 * components and the borders of the <code>Container</code>.
261 	 * 
262 	 * @serial
263 	 * @see #getHgap()
264 	 * @see #setHgap(int)
265 	 */
266 	protected int hgap;
267 
268 	/***
269 	 * The flow layout manager allows a seperation of components with gaps. The
270 	 * vertical gap will specify the space between rows and between the the rows
271 	 * and the borders of the <code>Container</code>.
272 	 * 
273 	 * @serial
274 	 * @see #getHgap()
275 	 * @see #setHgap(int)
276 	 */
277 	protected int vgap;
278 
279 }