I believe it could be quite useful for other project and release it under the Eclipse Public License (EPL).
The layout arranges components in a grid where all cells have equal dimensions. Number of columns and column width adapts repsonsive to the available width.
Row height adapt to column width using a configurable ratio.
To see it in action please take a look at the demo video:
Here comes the source code. Please leave the header with the license and copyright information
package biz.pinnau.dms.rcp;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
/**
* Released under Eclipse Public License (EPL) 1.0
*
* Copyright: Peter Pinnau (peter@pinnau.biz)
*
* Gridbased SWT Layout
*
* 1. All cells have equal dimensions
* 2. Cell widths increases/decreases automatically and adjusts to
* available width of the container
* 3. Cell height is calculated with a ratio + offset from calculated
* cell width: height = width * ratio + offset
* 4. Column count can be automatically calculated according to available width
*
* @author Peter Pinnau (peter@pinnau.biz)
* @version 1.0
*
* Last modified: 2016-10-11
*
* Class was implemented for System Concept DMS
*
* System Concept DMS - Das papierlose Büro
*
* www.pinnau.biz/dms.html
*
*/
public class ResponsiveGridLayout extends Layout {
/**
* Fixed number if columns. Default = 0 => adaptive number of columns
*/
private int fixedNumColumns = 0;
/**
* Mimimum column width
*/
private int minColumnWidth;
/**
* ratio to calculate row height
*/
public float ratio = 1f;
/**
* Offset for row height calculation
*/
public int offset = 0;
/**
* margin around grid
*/
public int margin = 0;
/**
* spacing between cells
*/
public int spacing = 10;
/**
* Creates an instance of the layout using a fixed number of columns
*
* @param numColumns
*/
public ResponsiveGridLayout(int numColumns, int minimumColumnWidth) {
this.fixedNumColumns = numColumns;
this.minColumnWidth = minimumColumnWidth;
}
/**
* Creates an instance of the layout with adaptive number of columns depending
* on available width and minColumnWidth
*
* @param columnCounts
*/
public ResponsiveGridLayout(int minimumColumnWidth) {
this.minColumnWidth = minimumColumnWidth;
}
private int getBoxHeight(int boxWidth) {
return (int) (boxWidth * ratio) + offset;
}
private int getNumColumns(int availableWidth) {
// Fixed number of columns
if (fixedNumColumns > 0) return fixedNumColumns;
// No available width specified
if (availableWidth == SWT.DEFAULT) {
// assume 1 column
return 1;
}
// Start with width of 1 column
int totalWidth = minColumnWidth + 2 * margin;
int numColumns = 0;
// Increase column count until totalWidth exceeds avaiblableWidth
while (totalWidth < availableWidth) {
// Add spacing + minColumnWidth (1 new column)
totalWidth = totalWidth + spacing + minColumnWidth;
numColumns++;
}
if (numColumns == 0) numColumns = 1;
return numColumns;
}
@Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Point size = new Point(0, 0);
// Get number of columns
int numColumns = getNumColumns(wHint);
int boxWidth = getAvailableBoxWidth(wHint, numColumns);
int componentCount = composite.getChildren().length;
int rows = (int) Math.ceil(componentCount / (double) numColumns);
if (rows == 0) rows = 1;
size.x = numColumns * boxWidth + (numColumns-1) * spacing + 2 * margin;
size.y = rows * getBoxHeight(boxWidth) + (rows-1) * spacing + 2 * margin;
return size;
}
/**
* Calculates the available cell width
*
* @param width
* @param numColumns
* @return
*/
private int getAvailableBoxWidth(int width, int numColumns) {
if (width == SWT.DEFAULT) return minColumnWidth;
int boxWidth = (width - 2 * margin - (numColumns * spacing)) / numColumns;
if (boxWidth < minColumnWidth) return minColumnWidth;
return boxWidth;
}
@Override
protected void layout(Composite composite, boolean flushCache) {
Control[] children = composite.getChildren();
// Get number of columns
int numColumns = getNumColumns(composite.getClientArea().width);
int boxWidth = getAvailableBoxWidth(composite.getSize().x, numColumns);
int boxHeight = getBoxHeight(boxWidth);
// Build the grid
int x = margin;
int y = margin;
for (int i=0; i<children.length; i++) {
if (i % numColumns == 0) {
x = margin;
if (i > 0) {
y = y + spacing + boxHeight;
} else {
y = margin;
}
} else {
x = x + boxWidth + spacing;
}
children[i].setSize(boxWidth, boxHeight);
children[i].setLocation(x, y);
}
}
}
The following example shows how to use the layout together with a ScrolledComposite.
scroll = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL );
container = new Composite(scroll, SWT.None);
// Create adaptive Grid
layout = new ResponsiveGridLayout(150);
layout.offset = 50;
layout.ratio = 1.5f;
layout.margin = 5;
layout.spacing = 5;
container.setLayout(layout);
// Set the child as the scrolled content of the ScrolledComposite
scroll.setContent(container);
// Expand both horizontally and vertically
scroll.setExpandHorizontal(true);
scroll.setExpandVertical(true);
scroll.addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event) {
scroll.setMinSize(container.computeSize(scroll.getClientArea().width, SWT.DEFAULT));
}
});
// Add some controls to container ...