blob: a2336a2ef6d6f1287ed901e789cda8aadd520a0d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.layout;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
/**
* GridLayoutFactory creates and initializes grid layouts. There are two ways to use GridLayoutFactory.
* Normally, it is used as a shorthand for writing "new GridLayout()" and initializing a bunch
* of fields. In this case the main benefit is a more concise syntax and the ability to create more
* than one identical GridLayout from the same factory. Changing a property of the factory will affect
* future layouts created by the factory, but has no effect on layouts that have already been created.
*
* <p>
* GridLayoutFactory can also generate grid data for all the controls in a layout. This is done with
* the generateLayout method. To use this feature:
* </p>
*
* <ol>
* <li>Create the composite</li>
* <li>Create all the controls in the composite</li>
* <li>Call generateLayout</li>
* </ol>
*
* <p>
* The order here is important. generateLayout must be called after all the child controls have
* been created. generateLayout will not change any layout data that has already been attached
* to a child control and it will not recurse into nested composites.
* </p>
*
* @since 3.2
*/
public final class GridLayoutFactory {
/**
* Template layout. The factory will create copies of this layout.
*/
private GridLayout l;
/**
* Creates a new GridLayoutFactory that will create copies of the given layout.
*
* @param l layout to copy
*/
private GridLayoutFactory(GridLayout l) {
this.l = l;
}
/**
* Creates a factory that creates copies of the given layout.
*
* @param l layout to copy
* @return a new GridLayoutFactory instance that creates copies of the given layout
*/
public static GridLayoutFactory createFrom(GridLayout l) {
return new GridLayoutFactory(copyLayout(l));
}
/**
* Creates a copy of the reciever.
*
* @return a copy of the reciever
*/
public GridLayoutFactory copy() {
return new GridLayoutFactory(create());
}
/**
* Creates a GridLayoutFactory that creates GridLayouts with the default SWT
* values.
*
* <p>
* Initial values are:
* </p>
*
* <ul>
* <li>numColumns(1)</li>
* <li>margins(5,5)</li>
* <li>spacing(5,5)</li>
* <li>equalWidth(false)</li>
* </ul>
*
* @return a GridLayoutFactory that creates GridLayouts as though created with
* their default constructor
* @see #fillDefaults
*/
public static GridLayoutFactory swtDefaults() {
return new GridLayoutFactory(new GridLayout());
}
/**
* Creates a GridLayoutFactory that creates GridLayouts with no margins and
* default dialog spacing.
*
* <p>
* Initial values are:
* </p>
*
* <ul>
* <li>numColumns(1)</li>
* <li>margins(0,0)</li>
* <li>spacing(LayoutConstants.getSpacing())</li>
* <li>equalWidth(false)</li>
* </ul>
*
* @return a GridLayoutFactory that creates GridLayouts as though created with
* their default constructor
* @see #swtDefaults
*/
public static GridLayoutFactory fillDefaults() {
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
Point defaultSpacing = LayoutConstants.getSpacing();
layout.horizontalSpacing = defaultSpacing.x;
layout.verticalSpacing = defaultSpacing.y;
return new GridLayoutFactory(layout);
}
/**
* Sets whether the columns should be forced to be equal width
*
* @param equal true iff the columns should be forced to be equal width
* @return this
*/
public GridLayoutFactory equalWidth(boolean equal) {
l.makeColumnsEqualWidth = equal;
return this;
}
/**
* Sets the spacing for layouts created with this factory. The spacing
* is the distance between cells within the layout.
*
* @param hSpacing horizontal spacing (pixels)
* @param vSpacing vertical spacing (pixels)
* @return this
* @see #margins
*/
public GridLayoutFactory spacing(int hSpacing, int vSpacing) {
l.horizontalSpacing = hSpacing;
l.verticalSpacing = vSpacing;
return this;
}
/**
* Sets the spacing for layouts created with this factory. The spacing
* is the distance between cells within the layout.
*
* @param spacing space between controls in the layout (pixels)
* @return this
* @see #margins
*/
public GridLayoutFactory spacing(Point spacing) {
l.horizontalSpacing = spacing.x;
l.verticalSpacing = spacing.y;
return this;
}
/**
* Sets the margins for layouts created with this factory. The margins
* are the distance between the outer cells and the edge of the layout.
*
* @param margins margin size (pixels)
* @return this
* @see #spacing
*/
public GridLayoutFactory margins(Point margins) {
l.marginWidth = margins.x;
l.marginHeight = margins.y;
return this;
}
/**
* Sets the margins for layouts created with this factory. The margins
* are the distance between the outer cells and the edge of the layout.
*
* @param x horizontal margin size (pixels)
* @param y vertical margin size (pixels)
* @return this
* @see #spacing
*/
public GridLayoutFactory margins(int x, int y) {
l.marginWidth = x;
l.marginHeight = y;
return this;
}
/**
* Sets the number of columns in the layout
*
* @param numColumns number of columns in the layout
* @return this
*/
public GridLayoutFactory numColumns(int numColumns) {
l.numColumns = numColumns;
return this;
}
/**
* Creates a new GridLayout, and initializes it with values from the factory.
*
* @return a new initialized GridLayout.
* @see #applyTo
*/
public GridLayout create() {
return copyLayout(l);
}
/**
* Creates a new GridLayout and attaches it to the given composite.
* Does not create the GridData of any of the controls in the composite.
*
* @param c composite whose layout will be set
* @see #generateLayout
* @see #create
* @see GridLayoutFactory
*/
public void applyTo(Composite c) {
c.setLayout(copyLayout(l));
}
/**
* Copies the given GridLayout instance
*
* @param l layout to copy
* @return a new GridLayout
*/
public static GridLayout copyLayout(GridLayout l) {
GridLayout result = new GridLayout(l.numColumns, l.makeColumnsEqualWidth);
result.horizontalSpacing = l.horizontalSpacing;
result.marginBottom = l.marginBottom;
result.marginHeight = l.marginHeight;
result.marginLeft = l.marginLeft;
result.marginRight = l.marginRight;
result.marginTop = l.marginTop;
result.marginWidth = l.marginWidth;
result.verticalSpacing = l.verticalSpacing;
return result;
}
/**
* Applies this layout to the given composite, and attaches default GridData
* to all immediate children that don't have one. The layout is generated using
* heuristics based on the widget types. In most cases, it will create exactly the same
* layout that would have been hardcoded by the programmer. In any situation
* where it does not produce the desired layout, the GridData for any child can be
* overridden by attaching the layout data before calling this method. In these cases,
* the special-case layout data can be hardcoded and the algorithm can supply defaults
* to the rest.
*
* <p>
* This must be called <b>AFTER</b> all of the child controls have been created and their
* layouts attached. This method will attach a layout to the given composite. If any new
* children are created after calling this method, their GridData must be created manually.
* The algorithm does not recurse into child composites. To generate all the layouts in
* a widget hierarchy, the method must be called bottom-up for each Composite.
* </p>
*
* <p>
* All controls are made to span a single cell. The algorithm tries to classify controls into one
* of the following categories:
* </p>
*
* <ul>
* <li>Pushbuttons: Set to a constant size large enough to fit their text and no smaller
* than the default button size.</li>
* <li>Wrapping with text (labels, read-only text boxes, etc.): override the preferred horizontal
* size with the default wrapping point, fill horizontally, grab horizontal space, keep the
* preferred vertical size</li>
* <li>Wrapping without text (toolbars, coolbars, etc.): fill align, don't grab, use the preferred size</li>
* <li>Horizontally scrolling controls (anything with horizontal scrollbars or where the user edits
* text and can cursor through it from left-to-right): override the preferred horizontal size with
* a constant, grab horizontal, fill horizontal.</li>
* <li>Vertically scrolling controls (anything with vertical scrollbars or where the user edits
* text and can cursor through it up and down): override the preferred vertical size with a constant,
* grab vertical, fill vertical</li>
* <li>Nested layouts: fill align both directions, grab along any dimension if the layout would
* be able to expand along that dimension.</li>
* <li>Non-wrapping non-scrollable read-only text: fill horizontally, center vertically, default size, don't grab </li>
* <li>Non-wrapping non-scrollable non-text: fill both, default size, don't grab</li>
* </ul>
*
* @param c composite whose layout will be generated
*/
public void generateLayout(Composite c) {
applyTo(c);
LayoutGenerator.generateLayout(c);
}
}