1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.gui.layout;
17
18 /**
19 * <p>
20 * A layout manager that deals with button bars for dialogs.
21 * </p>
22 * <p>
23 * With this layout manager typical horizontal button bars for dialogs can be
24 * created in an easy way. The button objects simply need to be added to the
25 * container, no constraints need to be passed. These button bars have the
26 * following properties:
27 * <ul>
28 * <li>All buttons have the same width. This is the width of the widest button.</li>
29 * <li>Between the buttons there is a gap, which can be configured.</li>
30 * <li>Margins can be defined for all directions. All margins and the gap
31 * between the buttons can be defined in several units.</li>
32 * <li>The alignment of the buttons can be defined. This can be left aligned
33 * (i.e. the right margin grows if more space is available in the dialog), right
34 * aligned (the left margins grows) or center aligned (both margins grow).</li>
35 * </ul>
36 * </p>
37 * <p>
38 * This class is a special implementation of <code>PercentLayoutBase</code>. It
39 * implements the button layout on top of a percent layout. As its ancestor this
40 * class is platform neutral, i.e. it can work together with different GUI
41 * libraries for which a {@link PercentLayoutPlatformAdapter} implementation is
42 * available.
43 * </p>
44 *
45 * @author Oliver Heger
46 * @version $Id: ButtonLayout.java 205 2012-01-29 18:29:57Z oheger $
47 */
48 public class ButtonLayout extends PercentLayoutBase
49 {
50 /** Constant for the default margin value. */
51 static final NumberWithUnit DEFAULT_MARGIN = new NumberWithUnit(2, Unit.DLU);
52
53 /** Constant for the default gap value. */
54 static final NumberWithUnit DEFAULT_GAP = new NumberWithUnit(1, Unit.DLU);
55
56 /** Constant for the number of rows of this layout. */
57 private static final int ROW_SIZE = 3;
58
59 /** Constant for the full weight factor. */
60 private static final int WEIGHT_FULL = 100;
61
62 /** Constant for the half weight factor. */
63 private static final int WEIGHT_HALF = 50;
64
65 /** Constant for no weight factor. */
66 private static final int WEIGHT_NULL = 0;
67
68 /**
69 * The serial version UID.
70 */
71 private static final long serialVersionUID = 20090730L;
72
73 /** Stores the top margin. */
74 private NumberWithUnit topMargin;
75
76 /** Stores the bottom margin. */
77 private NumberWithUnit bottomMargin;
78
79 /** Stores the left margin. */
80 private NumberWithUnit leftMargin;
81
82 /** Stores the right margin. */
83 private NumberWithUnit rightMargin;
84
85 /** Stores the width of the gap between the buttons. */
86 private NumberWithUnit gap;
87
88 /** Stores the alignment flag. */
89 private Alignment alignment;
90
91 /**
92 * Creates a new instance of <code>ButtonLayout</code>. All properties are
93 * set to default values.
94 */
95 public ButtonLayout()
96 {
97 leftMargin = DEFAULT_MARGIN;
98 rightMargin = DEFAULT_MARGIN;
99 topMargin = DEFAULT_MARGIN;
100 bottomMargin = DEFAULT_MARGIN;
101 gap = DEFAULT_GAP;
102 alignment = Alignment.RIGHT;
103 }
104
105 /**
106 * Returns the top margin.
107 *
108 * @return the top margin
109 */
110 public NumberWithUnit getTopMargin()
111 {
112 return topMargin;
113 }
114
115 /**
116 * Sets the top margin. This is the space above the buttons.
117 *
118 * @param topMargin the top margin (a <b>null</b> reference is converted to
119 * a value of 0)
120 */
121 public void setTopMargin(NumberWithUnit topMargin)
122 {
123 this.topMargin = NumberWithUnit.nonNull(topMargin);
124 }
125
126 /**
127 * Returns the bottom margin.
128 *
129 * @return the bottom margin
130 */
131 public NumberWithUnit getBottomMargin()
132 {
133 return bottomMargin;
134 }
135
136 /**
137 * Sets the bottom margin. This is the space below the buttons.
138 *
139 * @param bottomMargin the bottom margin
140 */
141 public void setBottomMargin(NumberWithUnit bottomMargin)
142 {
143 this.bottomMargin = NumberWithUnit.nonNull(bottomMargin);
144 }
145
146 /**
147 * Returns the left margin.
148 *
149 * @return the left margin
150 */
151 public NumberWithUnit getLeftMargin()
152 {
153 return leftMargin;
154 }
155
156 /**
157 * Sets the left margin. This is the space between the window's left edge
158 * and the first button. This value is fixed only if the button bar is left
159 * aligned; otherwise this space may grow.
160 *
161 * @param leftMargin the left margin (a <b>null</b> reference is converted
162 * to a value of 0)
163 */
164 public void setLeftMargin(NumberWithUnit leftMargin)
165 {
166 this.leftMargin = NumberWithUnit.nonNull(leftMargin);
167 }
168
169 /**
170 * Returns the right margin.
171 *
172 * @return the right margin
173 */
174 public NumberWithUnit getRightMargin()
175 {
176 return rightMargin;
177 }
178
179 /**
180 * Sets the right margin. This is the space between the window's right edge
181 * and the last button. This value is fixed only if the button bar is right
182 * aligned; otherwise this space may grow.
183 *
184 * @param rightMargin the right margin (a <b>null</b> reference is converted
185 * to a value of 0)
186 */
187 public void setRightMargin(NumberWithUnit rightMargin)
188 {
189 this.rightMargin = NumberWithUnit.nonNull(rightMargin);
190 }
191
192 /**
193 * Returns the width of the gap between the buttons.
194 *
195 * @return the gap
196 */
197 public NumberWithUnit getGap()
198 {
199 return gap;
200 }
201
202 /**
203 * Sets the width of the gap between the buttons.
204 *
205 * @param gap the gap's width (a <b>null</b> reference is converted to a
206 * value of 0)
207 */
208 public void setGap(NumberWithUnit gap)
209 {
210 this.gap = NumberWithUnit.nonNull(gap);
211 }
212
213 /**
214 * Returns the alignment of the button bar.
215 *
216 * @return the alignment
217 */
218 public Alignment getAlignment()
219 {
220 return alignment;
221 }
222
223 /**
224 * Sets the alignment of the button bar.
225 *
226 * @param alignment the new alignment (must not be <b>null</b>)
227 * @throws IllegalArgumentException if the alignment is <b>null</b>
228 */
229 public void setAlignment(Alignment alignment)
230 {
231 if (alignment == null)
232 {
233 throw new IllegalArgumentException("Alignment must not be null!");
234 }
235 this.alignment = alignment;
236 }
237
238 /**
239 * Initializes the whole layout. Creates a percent layout based on the
240 * current property values and the contained buttons.
241 *
242 * @param adapter the currently used platform adapter
243 */
244 @Override
245 protected void initCells(PercentLayoutPlatformAdapter adapter)
246 {
247 int buttonCount = adapter.getComponentCount();
248 int lastIndex = 2 * buttonCount;
249 initDimensions(lastIndex + 1, ROW_SIZE);
250 clearCells(lastIndex + 1, ROW_SIZE);
251
252 initRowConstraints();
253 initColumnConstraints(lastIndex, buttonCount);
254 insertButtons(adapter, buttonCount);
255 }
256
257 /**
258 * Initializes the row constraints.
259 */
260 protected void initRowConstraints()
261 {
262 CellConstraints.Builder cBuilder = getConstraintsBuilder();
263 setRowConstraints(0, cBuilder.withMinimumSize(getTopMargin()).create());
264 setRowConstraints(1, cBuilder.defaultRow().create());
265 setRowConstraints(2, cBuilder.withMinimumSize(getBottomMargin())
266 .create());
267 }
268
269 /**
270 * Initializes the column constraints.
271 *
272 * @param lastIndex the index of the last column
273 * @param buttonCount the number of buttons
274 */
275 protected void initColumnConstraints(int lastIndex, int buttonCount)
276 {
277 CellConstraints.Builder cBuilder = getConstraintsBuilder();
278 setColumnConstraints(0, cBuilder.withCellAlignment(CellAlignment.FULL)
279 .withMinimumSize(getLeftMargin()).withWeight(
280 calcWeightFactor(Alignment.LEFT)).create());
281 setColumnConstraints(lastIndex, cBuilder.withCellAlignment(
282 CellAlignment.FULL).withMinimumSize(getRightMargin())
283 .withWeight(calcWeightFactor(Alignment.RIGHT)).create());
284
285 CellConstraints ccGap = cBuilder.withMinimumSize(getGap()).create();
286 for (int i = 2; i < lastIndex - 1; i += 2)
287 {
288 setColumnConstraints(i, ccGap);
289 }
290
291 CellConstraints ccBtn = cBuilder.withCellAlignment(CellAlignment.FULL)
292 .withCellSize(CellSize.PREFERRED).create();
293 int[] buttonIndices = new int[buttonCount];
294 int btnIdx = 0;
295 for (int i = 1; i < lastIndex; i += 2, btnIdx++)
296 {
297 buttonIndices[btnIdx] = i;
298 setColumnConstraints(i, ccBtn);
299 }
300
301 if (buttonCount > 1)
302 {
303 addColumnGroup(CellGroup.fromArray(buttonIndices));
304 }
305 }
306
307 /**
308 * Inserts all buttons into the percent layout.
309 *
310 * @param adapter the platform adapter
311 * @param buttonCount the number of available buttons
312 */
313 protected void insertButtons(PercentLayoutPlatformAdapter adapter,
314 int buttonCount)
315 {
316 PercentData.Builder pcb = new PercentData.Builder();
317
318 for (int i = 0; i < buttonCount; i++)
319 {
320 PercentData pd = pcb.pos(2 * i + 1, 1);
321 initCell(adapter.getComponent(i), pd);
322 }
323 }
324
325 /**
326 * Calculates the weight factor for the left or right margin cell.
327 *
328 * @param align the alignment of this margin
329 * @return the weight factor for this margin cell
330 */
331 private int calcWeightFactor(Alignment align)
332 {
333 if (getAlignment() == Alignment.CENTER)
334 {
335 return WEIGHT_HALF;
336 }
337 else
338 {
339 return (getAlignment() != align) ? WEIGHT_FULL : WEIGHT_NULL;
340 }
341 }
342
343 /**
344 * An enumeration class for the alignment of a {@code ButtonLayout}. The
345 * alignment defines the horizontal orientation of the buttons in the
346 * layout.
347 *
348 * @author Oliver Heger
349 * @version $Id: ButtonLayout.java 205 2012-01-29 18:29:57Z oheger $
350 */
351 public static enum Alignment
352 {
353 /**
354 * The alignment <em>left</em>. All buttons are aligned to the left
355 * margin of the layout. If more space becomes available, the right
356 * margin grows.
357 */
358 LEFT,
359
360 /**
361 * The alignment <em>right</em>. All buttons are aligned to the right
362 * margin of the layout. If more space becomes available, the left
363 * margin grows.
364 */
365 RIGHT,
366
367 /**
368 * The alignment <em>center</em>. The buttons are centered in the
369 * hosting container. If more space becomes available, both the left and
370 * the right margin grow.
371 */
372 CENTER
373 }
374 }