blob: e939e9cd594931fec615a9a05459e2a427bf9b09 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.swt.layout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.*;
/**
* <code>FillLayout</code> is the simplest layout class. It lays out controls
* in a single row or column, forcing them to be the same size.
* <p>
* Initially, the controls will all be as tall as the tallest control, and as
* wide as the widest. <code>FillLayout</code> does not wrap, but you can
* specify margins and spacing. You might use it to lay out buttons in a task
* bar or tool bar, or to stack checkboxes in a <code>Group</code>.
* <code>FillLayout</code> can also be used when a <code>Composite</code>
* only has one child. For example, if a <code>Shell</code> has a single
* <code>Group</code> child, <code>FillLayout</code> will cause the
* <code>Group</code> to completely fill the <code>Shell</code> (if margins
* are 0).
* </p>
* <p>
* Example code: first a <code>FillLayout</code> is created and its type field
* is set, and then the layout is set into the <code>Composite</code>. Note
* that in a <code>FillLayout</code>, children are always the same size, and
* they fill all available space.
*
* <pre>
* FillLayout fillLayout = new FillLayout();
* fillLayout.type = SWT.VERTICAL;
* shell.setLayout( fillLayout );
* </pre>
*
* </p>
*/
public final class FillLayout extends Layout {
/**
* type specifies how controls will be positioned within the layout. The
* default value is HORIZONTAL. Possible values are:
* <ul>
* <li>HORIZONTAL: Position the controls horizontally from left to right</li>
* <li>VERTICAL: Position the controls vertically from top to bottom</li>
* </ul>
*/
public int type = SWT.HORIZONTAL;
/**
* marginWidth specifies the number of pixels of horizontal margin that will
* be placed along the left and right edges of the layout. The default value
* is 0.
*
* @since 3.0
*/
public int marginWidth = 0;
/**
* marginHeight specifies the number of pixels of vertical margin that will be
* placed along the top and bottom edges of the layout. The default value is
* 0.
*
* @since 3.0
*/
public int marginHeight = 0;
/**
* spacing specifies the number of pixels between the edge of one cell and the
* edge of its neighbouring cell. The default value is 0.
*
* @since 3.0
*/
public int spacing = 0;
/**
* Constructs a new instance of this class.
*/
public FillLayout() {
}
/**
* Constructs a new instance of this class given the type.
*
* @param type the type of fill layout
* @since 2.0
*/
public FillLayout( int type ) {
this.type = type;
}
protected Point computeSize( Composite composite,
int wHint,
int hHint,
boolean flushCache )
{
Control[] children = composite.getChildren();
int count = children.length;
int maxWidth = 0, maxHeight = 0;
for( int i = 0; i < count; i++ ) {
Control child = children[ i ];
int w = wHint, h = hHint;
if( count > 0 ) {
if( type == SWT.HORIZONTAL && wHint != SWT.DEFAULT ) {
w = Math.max( 0, ( wHint - ( count - 1 ) * spacing ) / count );
}
if( type == SWT.VERTICAL && hHint != SWT.DEFAULT ) {
h = Math.max( 0, ( hHint - ( count - 1 ) * spacing ) / count );
}
}
Point size = computeChildSize( child, w, h, flushCache );
maxWidth = Math.max( maxWidth, size.x );
maxHeight = Math.max( maxHeight, size.y );
}
int width = 0, height = 0;
if( type == SWT.HORIZONTAL ) {
width = count * maxWidth;
if( count != 0 )
width += ( count - 1 ) * spacing;
height = maxHeight;
} else {
width = maxWidth;
height = count * maxHeight;
if( count != 0 )
height += ( count - 1 ) * spacing;
}
width += marginWidth * 2;
height += marginHeight * 2;
if( wHint != SWT.DEFAULT )
width = wHint;
if( hHint != SWT.DEFAULT )
height = hHint;
return new Point( width, height );
}
Point computeChildSize( Control control,
int wHint,
int hHint,
boolean flushCache )
{
FillData data = ( FillData )control.getLayoutData();
if( data == null ) {
data = new FillData();
control.setLayoutData( data );
}
Point size = null;
if( wHint == SWT.DEFAULT && hHint == SWT.DEFAULT ) {
size = data.computeSize( control, wHint, hHint, flushCache );
} else {
// TEMPORARY CODE
int trimX, trimY;
if( control instanceof Scrollable ) {
Rectangle rect = ( ( Scrollable )control ).computeTrim( 0, 0, 0, 0 );
trimX = rect.width;
trimY = rect.height;
} else {
trimX = trimY = control.getBorderWidth() * 2;
}
int w = wHint == SWT.DEFAULT
? wHint
: Math.max( 0, wHint - trimX );
int h = hHint == SWT.DEFAULT
? hHint
: Math.max( 0, hHint - trimY );
size = data.computeSize( control, w, h, flushCache );
}
return size;
}
protected boolean flushCache( Control control ) {
Object data = control.getLayoutData();
if( data != null )
( ( FillData )data ).flushCache();
return true;
}
String getName() {
String string = getClass().getName();
int index = string.lastIndexOf( '.' );
if( index == -1 )
return string;
return string.substring( index + 1, string.length() );
}
protected void layout( Composite composite, boolean flushCache ) {
Rectangle rect = composite.getClientArea();
Control[] children = composite.getChildren();
int count = children.length;
if( count == 0 )
return;
int width = rect.width - marginWidth * 2;
int height = rect.height - marginHeight * 2;
if( type == SWT.HORIZONTAL ) {
width -= ( count - 1 ) * spacing;
int x = rect.x + marginWidth, extra = width % count;
int y = rect.y + marginHeight, cellWidth = width / count;
for( int i = 0; i < count; i++ ) {
Control child = children[ i ];
int childWidth = cellWidth;
if( i == 0 ) {
childWidth += extra / 2;
} else {
if( i == count - 1 )
childWidth += ( extra + 1 ) / 2;
}
child.setBounds( x, y, childWidth, height );
x += childWidth + spacing;
}
} else {
height -= ( count - 1 ) * spacing;
int x = rect.x + marginWidth, cellHeight = height / count;
int y = rect.y + marginHeight, extra = height % count;
for( int i = 0; i < count; i++ ) {
Control child = children[ i ];
int childHeight = cellHeight;
if( i == 0 ) {
childHeight += extra / 2;
} else {
if( i == count - 1 )
childHeight += ( extra + 1 ) / 2;
}
child.setBounds( x, y, width, childHeight );
y += childHeight + spacing;
}
}
}
/**
* Returns a string containing a concise, human-readable description of the
* receiver.
*
* @return a string representation of the layout
*/
public String toString() {
String string = getName() + " {";
string += "type=" + ( ( type == SWT.VERTICAL )
? "SWT.VERTICAL"
: "SWT.HORIZONTAL" ) + " ";
if( marginWidth != 0 )
string += "marginWidth=" + marginWidth + " ";
if( marginHeight != 0 )
string += "marginHeight=" + marginHeight + " ";
if( spacing != 0 )
string += "spacing=" + spacing + " ";
string = string.trim();
string += "}";
return string;
}
}