Mercurial > projects > dwt-addons
diff dwtx/draw2d/FlowLayout.d @ 98:95307ad235d9
Added Draw2d code, still work in progress
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 03 Aug 2008 00:52:14 +0200 |
parents | |
children | c3583c6ec027 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/draw2d/FlowLayout.d Sun Aug 03 00:52:14 2008 +0200 @@ -0,0 +1,466 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.draw2d.FlowLayout; + +import dwt.dwthelper.utils; +import dwtx.dwtxhelper.Collection; + +import dwtx.draw2d.geometry.Dimension; +import dwtx.draw2d.geometry.Rectangle; +import dwtx.draw2d.geometry.Transposer; +import dwtx.draw2d.AbstractHintLayout; +import dwtx.draw2d.IFigure; + +/** + * Lays out children in rows or columns, wrapping when the current row/column is filled. + * The aligment and spacing of rows in the parent can be configured. The aligment and + * spacing of children within a row can be configured. + */ +public class FlowLayout + : AbstractHintLayout +{ + +/** Constant to specify components to be aligned in the center */ +public static const int ALIGN_CENTER = 0; +/** Constant to specify components to be aligned on the left/top */ +public static const int ALIGN_LEFTTOP = 1; +/** Constant to specify components to be aligned on the right/bottom */ +public static const int ALIGN_RIGHTBOTTOM = 2; + +/** Constant to specify components should be layed out horizontally */ +public static const bool HORIZONTAL = true; +/** Constant to specify components should be layed out vertically */ +public static const bool VERTICAL = false; + +/** The horizontal property. */ +protected bool horizontal = true; +/** + * The property that determines whether leftover space at the end of a row/column should + * be filled by the last item in that row/column. + */ +protected bool fill = false; + +/** The transposer used in converting horizontal layout to vertical. */ +protected Transposer transposer; +private void instanceInit(){ + transposer = new Transposer(); + transposer.setEnabled(!horizontal); +} + +/** The alignment along the major axis. */ +protected int majorAlignment = ALIGN_LEFTTOP; +/** The alignment along the minor axis. */ +protected int minorAlignment = ALIGN_LEFTTOP; +/** The spacing along the minor axis. */ +protected int minorSpacing = 5; +/** The spacing along the major axis. */ +protected int majorSpacing = 5; +protected WorkingData data = null; + +/** + * Holds the necessary information for layout calculations. + */ +protected class WorkingData { + public int rowHeight, rowWidth, rowCount, rowX, rowY, maxWidth; + public Rectangle[] bounds; + public Rectangle area; + public IFigure row[]; +} + +/** + * Constructs a FlowLayout with horizontal orientation. + * @since 2.0 + */ +public this() { + instanceInit(); +} + +/** + * Constructs a FlowLayout whose orientation is given in the input. + * @param isHorizontal <code>true</code> if the layout should be horizontal + * @since 2.0 + */ +public this(bool isHorizontal) { + instanceInit(); + setHorizontal(isHorizontal); +} + +/** + * @see dwtx.draw2d.AbstractLayout#calculatePreferredSize(IFigure, int, int) + */ +protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) { + // Subtract out the insets from the hints + if (wHint > -1) + wHint = Math.max(0, wHint - container.getInsets().getWidth()); + if (hHint > -1) + hHint = Math.max(0, hHint - container.getInsets().getHeight()); + + // Figure out the new hint that we are interested in based on the orientation + // Ignore the other hint (by setting it to -1). NOTE: The children of the + // parent figure will then be asked to ignore that hint as well. + int maxWidth; + if (isHorizontal()) { + maxWidth = wHint; + hHint = -1; + } else { + maxWidth = hHint; + wHint = -1; + } + if (maxWidth < 0) { + maxWidth = Integer.MAX_VALUE; + } + + // The preferred dimension that is to be calculated and returned + Dimension prefSize = new Dimension(); + + List children = container.getChildren(); + int width = 0; + int height = 0; + IFigure child; + Dimension childSize; + + //Build the sizes for each row, and update prefSize accordingly + for (int i = 0; i < children.size(); i++) { + child = cast(IFigure)children.get(i); + childSize = transposer.t(getChildSize(child, wHint, hHint)); + if (i is 0) { + width = childSize.width; + height = childSize.height; + } else if (width + childSize.width + getMinorSpacing() > maxWidth) { + // The current row is full, start a new row. + prefSize.height += height + getMajorSpacing(); + prefSize.width = Math.max(prefSize.width, width); + width = childSize.width; + height = childSize.height; + } else { + // The current row can fit another child. + width += childSize.width + getMinorSpacing(); + height = Math.max(height, childSize.height); + } + } + + // Flush out the last row's data + prefSize.height += height; + prefSize.width = Math.max(prefSize.width, width); + + // Transpose the dimension back, and compensate for the border. + prefSize = transposer.t(prefSize); + prefSize.width += container.getInsets().getWidth(); + prefSize.height += container.getInsets().getHeight(); + prefSize.union_(getBorderPreferredSize(container)); + + return prefSize; +} + +/** + * Provides the given child's preferred size. + * + * @param child the Figure whose preferred size needs to be calculated + * @param wHint the width hint + * @param hHint the height hint + * @return the child's preferred size + */ +protected Dimension getChildSize(IFigure child, int wHint, int hHint) { + return child.getPreferredSize(wHint, hHint); +} + + +/** + * Returns the alignment used for an entire row/column. + * <P> + * Possible values are : + * <ul> + * <li>{@link #ALIGN_CENTER} + * <li>{@link #ALIGN_LEFTTOP} + * <li>{@link #ALIGN_RIGHTBOTTOM} + * </ul> + * + * @return the major alignment + * @since 2.0 + */ +public int getMajorAlignment() { + return majorAlignment; +} + +/** + * Returns the spacing in pixels to be used between children in the direction parallel to + * the layout's orientation. + * @return the major spacing + */ +public int getMajorSpacing() { + return majorSpacing; +} + +/** + * Returns the alignment used for children within a row/column. + * <P> + * Possible values are : + * <ul> + * <li>{@link #ALIGN_CENTER} + * <li>{@link #ALIGN_LEFTTOP} + * <li>{@link #ALIGN_RIGHTBOTTOM} + * </ul> + * + * @return the minor alignment + * @since 2.0 + */ +public int getMinorAlignment() { + return minorAlignment; +} + +/** + * Returns the spacing to be used between children within a row/column. + * @return the minor spacing + */ +public int getMinorSpacing() { + return minorSpacing; +} + +/** + * Initializes the state of row data, which is internal to the layout process. + */ +protected void initRow() { + data.rowX = 0; + data.rowHeight = 0; + data.rowWidth = 0; + data.rowCount = 0; +} + +/** + * Initializes state data for laying out children, based on the Figure given as input. + * + * @param parent the parent figure + * @since 2.0 + */ +protected void initVariables(IFigure parent) { + data.row = new IFigure[parent.getChildren().size()]; + data.bounds = new Rectangle[data.row.length]; + data.maxWidth = data.area.width; +} + +/** + * Returns <code>true</code> if the orientation of the layout is horizontal. + * + * @return <code>true</code> if the orientation of the layout is horizontal + * @since 2.0 + */ +public bool isHorizontal() { + return horizontal; +} + +/** + * @see dwtx.draw2d.AbstractHintLayout#isSensitiveHorizontally(IFigure) + */ +protected bool isSensitiveHorizontally(IFigure parent) { + return isHorizontal(); +} + +/** + * @see dwtx.draw2d.AbstractHintLayout#isSensitiveVertically(IFigure) + */ +protected bool isSensitiveVertically(IFigure parent) { + return !isHorizontal(); +} + +/** + * @see dwtx.draw2d.LayoutManager#layout(IFigure) + */ +public void layout(IFigure parent) { + data = new WorkingData(); + Rectangle relativeArea = parent.getClientArea(); + data.area = transposer.t(relativeArea); + + Iterator iterator = parent.getChildren().iterator(); + int dx; + + //Calculate the hints to be passed to children + int wHint = -1; + int hHint = -1; + if (isHorizontal()) + wHint = parent.getClientArea().width; + else + hHint = parent.getClientArea().height; + + initVariables(parent); + initRow(); + int i = 0; + while (iterator.hasNext()) { + IFigure f = cast(IFigure)iterator.next(); + Dimension pref = transposer.t(getChildSize(f, wHint, hHint)); + Rectangle r = new Rectangle(0, 0, pref.width, pref.height); + + if (data.rowCount > 0) { + if (data.rowWidth + pref.width > data.maxWidth) + layoutRow(parent); + } + r.x = data.rowX; + r.y = data.rowY; + dx = r.width + getMinorSpacing(); + data.rowX += dx; + data.rowWidth += dx; + data.rowHeight = Math.max(data.rowHeight, r.height); + data.row [data.rowCount] = f; + data.bounds[data.rowCount] = r; + data.rowCount++; + i++; + } + if (data.rowCount !is 0) + layoutRow(parent); + data = null; +} + +/** + * Layouts one row of components. This is done based on the layout's orientation, minor + * alignment and major alignment. + * + * @param parent the parent figure + * @since 2.0 + */ +protected void layoutRow(IFigure parent) { + int majorAdjustment = 0; + int minorAdjustment = 0; + int correctMajorAlignment = majorAlignment; + int correctMinorAlignment = minorAlignment; + + majorAdjustment = data.area.width - data.rowWidth + getMinorSpacing(); + + switch (correctMajorAlignment) { + case ALIGN_LEFTTOP: + majorAdjustment = 0; + break; + case ALIGN_CENTER: + majorAdjustment /= 2; + break; + case ALIGN_RIGHTBOTTOM: + break; + } + + for (int j = 0; j < data.rowCount; j++) { + if (fill) { + data.bounds[j].height = data.rowHeight; + } else { + minorAdjustment = data.rowHeight - data.bounds[j].height; + switch (correctMinorAlignment) { + case ALIGN_LEFTTOP: + minorAdjustment = 0; + break; + case ALIGN_CENTER: + minorAdjustment /= 2; + break; + case ALIGN_RIGHTBOTTOM: + break; + } + data.bounds[j].y += minorAdjustment; + } + data.bounds[j].x += majorAdjustment; + + setBoundsOfChild(parent, data.row[j], transposer.t(data.bounds[j])); + } + data.rowY += getMajorSpacing() + data.rowHeight; + initRow(); +} + +/** + * Sets the given bounds for the child figure input. + * + * @param parent the parent figure + * @param child the child figure + * @param bounds the size of the child to be set + * @since 2.0 + */ +protected void setBoundsOfChild(IFigure parent, IFigure child, Rectangle bounds) { + parent.getClientArea(Rectangle.SINGLETON); + bounds.translate(Rectangle.SINGLETON.x, Rectangle.SINGLETON.y); + child.setBounds(bounds); +} + +/** + * Sets flag based on layout orientation. If in horizontal orientation, all figures will + * have the same height. If in vertical orientation, all figures will have the same width. + * + * @param value fill state desired + * @since 2.0 + */ +public void setStretchMinorAxis(bool value) { + fill = value; +} + +/** + * Sets the orientation of the layout. + * + * @param flag <code>true</code> if this layout should be horizontal + * @since 2.0 + */ +public void setHorizontal(bool flag) { + if (horizontal is flag) return; + invalidate(); + horizontal = flag; + transposer.setEnabled(!horizontal); +} + +/** + * Sets the alignment for an entire row/column within the parent figure. + * <P> + * Possible values are : + * <ul> + * <li>{@link #ALIGN_CENTER} + * <li>{@link #ALIGN_LEFTTOP} + * <li>{@link #ALIGN_RIGHTBOTTOM} + * </ul> + * + * @param align the major alignment + * @since 2.0 + */ +public void setMajorAlignment(int align_) { + majorAlignment = align_; +} + +/** + * Sets the spacing in pixels to be used between children in the direction parallel to the + * layout's orientation. + * + * @param n the major spacing + * @since 2.0 + */ +public void setMajorSpacing(int n) { + majorSpacing = n; +} + +/** + * Sets the alignment to be used within a row/column. + * <P> + * Possible values are : + * <ul> + * <li>{@link #ALIGN_CENTER} + * <li>{@link #ALIGN_LEFTTOP} + * <li>{@link #ALIGN_RIGHTBOTTOM} + * </ul> + * + * @param align the minor alignment + * @since 2.0 + */ +public void setMinorAlignment(int align_) { + minorAlignment = align_; +} + +/** + * Sets the spacing to be used between children within a row/column. + * + * @param n the minor spacing + * @since 2.0 + */ +public void setMinorSpacing(int n) { + minorSpacing = n; +} + +}