Mercurial > projects > dwt-addons
diff dwtx/jface/layout/AbstractColumnLayout.d @ 10:b6c35faf97c8
Viewers
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 31 Mar 2008 00:47:19 +0200 |
parents | |
children | ea8ff534f622 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/layout/AbstractColumnLayout.d Mon Mar 31 00:47:19 2008 +0200 @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2006, 2007 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 (original file dwtx.ui.texteditor.templates.ColumnLayout) + * Tom Schindl <tom.schindl@bestsolution.at> - refactored to be widget independent (bug 171824) + * - fix for bug 178280, 184342, 184045 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.jface.layout.AbstractColumnLayout; + + + +import dwt.DWT; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Composite; +import dwt.widgets.Event; +import dwt.widgets.Layout; +import dwt.widgets.Listener; +import dwt.widgets.Scrollable; +import dwt.widgets.Widget; +import dwtx.core.runtime.Assert; +import dwtx.jface.util.Policy; +import dwtx.jface.viewers.ColumnLayoutData; +import dwtx.jface.viewers.ColumnPixelData; +import dwtx.jface.viewers.ColumnWeightData; +import dwtx.jface.viewers.TableLayout; + +import dwt.dwthelper.utils; + +/** + * The AbstractColumnLayout is a {@link Layout} used to set the size of a table + * in a consistent way even during a resize unlike a {@link TableLayout} which + * only sets initial sizes. + * + * <p><b>You can only add the layout to a container whose + * only child is the table/tree control you want the layouts applied to.</b> + * </p> + * + * @since 3.3 + */ +abstract class AbstractColumnLayout : Layout { + /** + * The number of extra pixels taken as horizontal trim by the table column. + * To ensure there are N pixels available for the content of the column, + * assign N+COLUMN_TRIM for the column width. + * + * @since 3.1 + */ + private static int COLUMN_TRIM; + + static const bool IS_GTK; + + static const String LAYOUT_DATA; + + static this(){ + COLUMN_TRIM = "carbon".equals(DWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$ + IS_GTK = "gtk".equals(DWT.getPlatform());//$NON-NLS-1$ + LAYOUT_DATA = Policy.JFACE ~ ".LAYOUT_DATA"; //$NON-NLS-1$ + } + + private bool inupdateMode = false; + + private bool relayout = true; + + private Listener resizeListener; + private void init_resizeListener(){ + resizeListener = new class Listener { + + public void handleEvent(Event event) { + if( ! inupdateMode ) { + updateColumnData(event.widget); + } + } + + }; + } + public this(){ + init_resizeListener(); + } + + /** + * Adds a new column of data to this table layout. + * + * @param column + * the column + * + * @param data + * the column layout data + */ + public void setColumnData(Widget column, ColumnLayoutData data) { + + if( column.getData(LAYOUT_DATA) is null ) { + column.addListener(DWT.Resize, resizeListener); + } + + column.setData(LAYOUT_DATA, data); + } + + /** + * Compute the size of the table or tree based on the ColumnLayoutData and + * the width and height hint. + * + * @param scrollable + * the widget to compute + * @param wHint + * the width hint + * @param hHint + * the height hint + * @return Point where x is the width and y is the height + */ + private Point computeTableTreeSize(Scrollable scrollable, int wHint, + int hHint) { + Point result = scrollable.computeSize(wHint, hHint); + + int width = 0; + int size = getColumnCount(scrollable); + for (int i = 0; i < size; ++i) { + ColumnLayoutData layoutData = getLayoutData(scrollable,i); + if ( auto col = cast(ColumnPixelData)layoutData) { + width += col.width; + if (col.addTrim) { + width += COLUMN_TRIM; + } + } else if ( auto col = cast(ColumnWeightData)layoutData ) { + width += col.minimumWidth; + } else { + Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$ + } + } + if (width > result.x) + result.x = width; + + return result; + } + + /** + * Layout the scrollable based on the supplied width and area. Only increase + * the size of the scrollable if increase is <code>true</code>. + * + * @param scrollable + * @param width + * @param area + * @param increase + */ + private void layoutTableTree(Scrollable scrollable, int width, + Rectangle area, bool increase) { + int size = getColumnCount(scrollable); + int[] widths = new int[size]; + + int[] weightIteration = new int[size]; + int numberOfWeightColumns = 0; + + int fixedWidth = 0; + int minWeightWidth = 0; + int totalWeight = 0; + + // First calc space occupied by fixed columns + for (int i = 0; i < size; i++) { + ColumnLayoutData col = getLayoutData(scrollable,i); + if ( auto cpd = cast(ColumnPixelData)col ) { + int pixels = cpd.width; + if (cpd.addTrim) { + pixels += COLUMN_TRIM; + } + widths[i] = pixels; + fixedWidth += pixels; + } else if ( auto cw = cast(ColumnWeightData) col ) { + weightIteration[numberOfWeightColumns] = i; + numberOfWeightColumns++; + totalWeight += cw.weight; + minWeightWidth += cw.minimumWidth; + widths[i] = cw.minimumWidth; + } else { + Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$ + } + } + + // Do we have columns that have a weight? + int restIncludingMinWidths = width - fixedWidth; + int rest = restIncludingMinWidths - minWeightWidth; + if (numberOfWeightColumns > 0 && rest > 0) { + + // Modify the weights to reflect what each column already + // has due to its minimum. Otherwise, columns with low + // minimums get discriminated. + int totalWantedPixels = 0; + int[] wantedPixels = new int[numberOfWeightColumns]; + for (int i = 0; i < numberOfWeightColumns; i++) { + ColumnWeightData cw = cast(ColumnWeightData) getLayoutData(scrollable,weightIteration[i]); + wantedPixels[i] = totalWeight is 0 ? 0 : cw.weight + * restIncludingMinWidths / totalWeight; + totalWantedPixels += wantedPixels[i]; + } + + // Now distribute the rest to the columns with weight. + int totalDistributed = 0; + for (int i = 0; i < numberOfWeightColumns; ++i) { + int pixels = totalWantedPixels is 0 ? 0 : wantedPixels[i] + * rest / totalWantedPixels; + totalDistributed += pixels; + widths[weightIteration[i]] += pixels; + } + + // Distribute any remaining pixels to columns with weight. + int diff = rest - totalDistributed; + for (int i = 0; diff > 0; i = ((i + 1) % numberOfWeightColumns)) { + ++widths[weightIteration[i]]; + --diff; + } + } + + if (increase) { + scrollable.setSize(area.width, area.height); + } + + inupdateMode = true; + setColumnWidths(scrollable, widths); + scrollable.update(); + inupdateMode = false; + + if (!increase) { + scrollable.setSize(area.width, area.height); + } + } + + /* + * (non-Javadoc) + * + * @see dwt.widgets.Layout#computeSize(dwt.widgets.Composite, + * int, int, bool) + */ + protected Point computeSize(Composite composite, int wHint, int hHint, + bool flushCache) { + return computeTableTreeSize(getControl(composite), wHint, hHint); + } + + /* + * (non-Javadoc) + * + * @see dwt.widgets.Layout#layout(dwt.widgets.Composite, + * bool) + */ + protected void layout(Composite composite, bool flushCache) { + Rectangle area = composite.getClientArea(); + Scrollable table = getControl(composite); + int tableWidth = table.getSize().x; + int trim = computeTrim(area, table, tableWidth); + int width = Math.max(0, area.width - trim); + + if (width > 1) + layoutTableTree(table, width, area, tableWidth < area.width); + + // For the first time we need to relayout because Scrollbars are not + // calculate appropriately + if (relayout) { + relayout = false; + composite.layout(); + } + } + + /** + * Compute the area required for trim. + * + * @param area + * @param scrollable + * @param currentWidth + * @return int + */ + private int computeTrim(Rectangle area, Scrollable scrollable, + int currentWidth) { + int trim; + + if (currentWidth > 1) { + trim = currentWidth - scrollable.getClientArea().width; + } else { + // initially, the table has no extend and no client area - use the + // border with + // plus some padding as educated guess + trim = 2 * scrollable.getBorderWidth() + 1; + } + + return trim; + } + + /** + * Get the control being laid out. + * + * @param composite + * the composite with the layout + * @return {@link Scrollable} + */ + Scrollable getControl(Composite composite) { + return cast(Scrollable) composite.getChildren()[0]; + } + + /** + * Get the number of columns for the receiver. + * + * @return the number of columns + */ + abstract int getColumnCount(Scrollable tableTree); + + /** + * Set the widths of the columns. + * + * @param widths + */ + abstract void setColumnWidths(Scrollable tableTree, int[] widths); + + abstract ColumnLayoutData getLayoutData(Scrollable tableTree, int columnIndex); + + abstract void updateColumnData(Widget column); +}