/* * */ package org.eclipse.papyrus.uml.diagram.common.draw2d; import java.util.List; import org.eclipse.draw2d.AbstractHintLayout; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.draw2d.geometry.Transposer; // TODO: Auto-generated Javadoc /** * Arranges figures in a single row or column. Orientation can be set to produce * either a row or column layout. This layout tries to fit all children within * the parent's client area. To do this, it compresses the children by some * amount, but will not compress them smaller than their minimum size. If a * child's preferred size is smaller than the row's or column's minor dimension, * the layout can be configured to stretch the child. */ public class LeftToolbarLayout extends AbstractHintLayout { /** Space in pixels between Figures *. */ protected int spacing; /** Sets whether children should "stretch" with their container *. */ protected boolean matchWidth; /** Orientation of layout *. */ protected boolean horizontal = false; /** Alignment of layout *. */ protected int minorAlignment; /** Constant for center alignment *. */ public static final int ALIGN_CENTER = 0; /** Constant for top-left alignment *. */ public static final int ALIGN_TOPLEFT = 1; /** Constant for bottom-right alignment *. */ public static final int ALIGN_BOTTOMRIGHT = 2; /** Constant for horizontal alignment *. */ // @unused public static final boolean HORIZONTAL = true; /** Constant for vertical alignment *. */ // @unused public static final boolean VERTICAL = false; /** Transposer object used in layout calculations *. */ protected Transposer transposer; { transposer = new Transposer(); transposer.setEnabled(horizontal); } /** * Constructs a vertically oriented ToolbarLayout with child spacing of 0 * pixels, matchWidth <code>true</code>, and {@link #ALIGN_TOPLEFT} alignment. * * @since 2.0 */ public LeftToolbarLayout() { spacing = 0; matchWidth = true; minorAlignment = ALIGN_TOPLEFT; horizontal = false; } /** * Constructs a ToolbarLayout with a specified orientation. Default values * are: child spacing 0 pixels, matchWidth <code>false</code>, and {@link #ALIGN_TOPLEFT} alignment. * * @param isHorizontal * whether the children are oriented horizontally * * @since 2.0 */ // @unused public LeftToolbarLayout(boolean isHorizontal) { horizontal = isHorizontal; transposer.setEnabled(horizontal); spacing = 0; matchWidth = false; minorAlignment = ALIGN_TOPLEFT; } /** * Calculate children size. * * @param children * the children * @param wHint * the w hint * @param hHint * the h hint * @param preferred * the preferred * * @return the dimension */ private Dimension calculateChildrenSize(List children, int wHint, int hHint, boolean preferred) { Dimension childSize; IFigure child; int height = 0, width = 0; for(int i = 0; i < children.size(); i++) { child = (IFigure)children.get(i); childSize = transposer.t(preferred ? child.getPreferredSize(wHint, hHint) : child.getMinimumSize(wHint, hHint)); height += childSize.height; width = Math.max(width, childSize.width); } return new Dimension(width, height); } /** * Calculates the minimum size of the container based on the given hints. If * this is a vertically-oriented Toolbar Layout, then only the widthHint is * respected (which means that the children can be as tall as they desire). * In this case, the minimum width is that of the widest child, and the * minimum height is the sum of the minimum heights of all children, plus * the spacing between them. The border and insets of the container figure * are also accounted for. * * @param container * the figure whose minimum size has to be calculated * @param wHint * the width hint (the desired width of the container) * @param hHint * the height hint (the desired height of the container) * * @return the minimum size of the container * * @see #getMinimumSize(IFigure, int, int) * @since 2.1 */ @Override protected Dimension calculateMinimumSize(IFigure container, int wHint, int hHint) { Insets insets = container.getInsets(); if(isHorizontal()) { wHint = -1; if(hHint >= 0) { hHint = Math.max(0, hHint - insets.getHeight()); } } else { hHint = -1; if(wHint >= 0) { wHint = Math.max(0, wHint - insets.getWidth()); } } List children = container.getChildren(); Dimension minSize = calculateChildrenSize(children, wHint, hHint, false); // Do a second pass, if necessary if(wHint >= 0 && minSize.width > wHint) { minSize = calculateChildrenSize(children, minSize.width, hHint, false); } else if(hHint >= 0 && minSize.width > hHint) { minSize = calculateChildrenSize(children, wHint, minSize.width, false); } minSize.height += Math.max(0, children.size() - 1) * spacing; return transposer.t(minSize).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container)); } /** * Calculates the preferred size of the container based on the given hints. * If this is a vertically-oriented Toolbar Layout, then only the widthHint * is respected (which means that the children can be as tall as they * desire). In this case, the preferred width is that of the widest child, * and the preferred height is the sum of the preferred heights of all * children, plus the spacing between them. The border and insets of the * container figure are also accounted for. * * @param container * the figure whose preferred size has to be calculated * @param wHint * the width hint (the desired width of the container) * @param hHint * the height hint (the desired height of the container) * * @return the preferred size of the container * * @see #getPreferredSize(IFigure, int, int) * @since 2.0 */ @Override protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) { Insets insets = container.getInsets(); if(isHorizontal()) { wHint = -1; if(hHint >= 0) { hHint = Math.max(0, hHint - insets.getHeight()); } } else { hHint = -1; if(wHint >= 0) { wHint = Math.max(0, wHint - insets.getWidth()); } } List children = container.getChildren(); Dimension prefSize = calculateChildrenSize(children, wHint, hHint, true); // Do a second pass, if necessary if(wHint >= 0 && prefSize.width > wHint) { prefSize = calculateChildrenSize(children, prefSize.width, hHint, true); } else if(hHint >= 0 && prefSize.width > hHint) { prefSize = calculateChildrenSize(children, wHint, prefSize.width, true); } prefSize.height += Math.max(0, children.size() - 1) * spacing; return transposer.t(prefSize).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container)); } /** * Returns the minor aligment of the layout. Minor minor axis is the axis * perpindicular to the overall orientation set in the contructor. * * @return the minor aligment */ // @unused public int getMinorAlignment() { return minorAlignment; } /** * Gets the spacing. * * @return the spacing between children */ // @unused public int getSpacing() { return spacing; } /** * Returns <code>true</code> if stretch minor axis has been enabled. The * default value is false. * * @return <code>true</code> if stretch minor axis is enabled */ // @unused public boolean getStretchMinorAxis() { return matchWidth; } /** * Checks if is horizontal. * * @return whether the orientation of the layout is horizontal * * @since 2.0 */ public boolean isHorizontal() { return horizontal; } /** * Checks if is sensitive horizontally. * * @param parent * the parent * * @return true, if checks if is sensitive horizontally * * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveHorizontally(IFigure) */ @Override protected boolean isSensitiveHorizontally(IFigure parent) { return !isHorizontal(); } /** * Checks if is sensitive vertically. * * @param parent * the parent * * @return true, if checks if is sensitive vertically * * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveVertically(IFigure) */ @Override protected boolean isSensitiveVertically(IFigure parent) { return isHorizontal(); } /** * Layout. * * @param parent * the parent * * @see org.eclipse.draw2d.LayoutManager#layout(IFigure) */ public void layout(IFigure parent) { List children = parent.getChildren(); int numChildren = children.size(); Rectangle clientArea = transposer.t(parent.getClientArea()); int x = clientArea.x; int y = clientArea.y; int availableHeight = clientArea.height; // parent.setBorder(null); Dimension prefSizes[] = new Dimension[numChildren]; Dimension minSizes[] = new Dimension[numChildren]; // Calculate the width and height hints. If it's a vertical // ToolBarLayout, // then ignore the height hint (set it to -1); otherwise, ignore the // width hint. These hints will be passed to the children of the parent // figure when getting their preferred size. int wHint = -1; int hHint = -1; if(isHorizontal()) { hHint = parent.getClientArea(Rectangle.SINGLETON).height; } else { wHint = parent.getClientArea(Rectangle.SINGLETON).width; } /* * Calculate sum of preferred heights of all children(totalHeight). * Calculate sum of minimum heights of all children(minHeight). Cache * Preferred Sizes and Minimum Sizes of all children. * * totalHeight is the sum of the preferred heights of all children * totalMinHeight is the sum of the minimum heights of all children * prefMinSumHeight is the sum of the difference between all children's * preferred heights and minimum heights. (This is used as a ratio to * calculate how much each child will shrink). */ IFigure child; int totalHeight = 0; int totalMinHeight = 0; int prefMinSumHeight = 0; for(int i = 0; i < numChildren; i++) { child = (IFigure)children.get(i); prefSizes[i] = transposer.t(child.getPreferredSize(wHint, hHint)); minSizes[i] = transposer.t(child.getMinimumSize(wHint, hHint)); totalHeight += prefSizes[i].height; totalMinHeight += minSizes[i].height; } totalHeight += (numChildren - 1) * spacing; totalMinHeight += (numChildren - 1) * spacing; prefMinSumHeight = totalHeight - totalMinHeight; /* * The total amount that the children must be shrunk is the sum of the * preferred Heights of the children minus Max(the available area and * the sum of the minimum heights of the children). * * amntShrinkHeight is the combined amount that the children must shrink * amntShrinkCurrentHeight is the amount each child will shrink * respectively */ int amntShrinkHeight = totalHeight - Math.max(availableHeight, totalMinHeight); if(amntShrinkHeight < 0) { amntShrinkHeight = 0; } for(int i = 0; i < numChildren; i++) { int amntShrinkCurrentHeight = 0; int prefHeight = prefSizes[i].height; int minHeight = minSizes[i].height; int prefWidth = prefSizes[i].width; int minWidth = minSizes[i].width; Rectangle newBounds = new Rectangle(x, y, prefWidth, prefHeight); child = (IFigure)children.get(i); if(prefMinSumHeight != 0) { amntShrinkCurrentHeight = (prefHeight - minHeight) * amntShrinkHeight / (prefMinSumHeight); } int width = Math.min(prefWidth, transposer.t(child.getMaximumSize()).width); if(matchWidth) { width = transposer.t(child.getMaximumSize()).width; } width = Math.max(minWidth, Math.min(clientArea.width, width)); newBounds.width = width; int adjust = clientArea.width - width; switch(minorAlignment) { case ALIGN_TOPLEFT: adjust = 0; break; case ALIGN_CENTER: adjust /= 2; break; case ALIGN_BOTTOMRIGHT: break; } newBounds.x += adjust; newBounds.height -= amntShrinkCurrentHeight; child.setBounds(transposer.t(newBounds)); amntShrinkHeight -= amntShrinkCurrentHeight; prefMinSumHeight -= (prefHeight - minHeight); y += newBounds.height + spacing; } } /** * Sets the alignment of the children contained in the layout. Possible * values are {@link #ALIGN_CENTER}, {@link #ALIGN_BOTTOMRIGHT} and {@link #ALIGN_TOPLEFT}. * * @param align * the minor alignment * * @since 2.0 */ // @unused public void setMinorAlignment(int align) { minorAlignment = align; } /** * Sets the amount of space between children. * * @param space * the amount of space between children * * @since 2.0 */ // @unused public void setSpacing(int space) { spacing = space; } /** * Sets children's width (if vertically oriented) or height (if horizontally * oriented) to stretch with their container. * * @param match * whether to stretch children * * @deprecated use {@link #setStretchMinorAxis(boolean)} * @since 2.0 */ @Deprecated public void setMatchWidth(boolean match) { matchWidth = match; } /** * Causes children that are smaller in the dimension of the minor axis to be * stretched to fill the minor axis. The minor axis is the opposite of the * orientation. * * @param stretch * whether to stretch children * * @since 2.0 */ public void setStretchMinorAxis(boolean stretch) { matchWidth = stretch; } /** * Sets the orientation of the children in the ToolbarLayout. * * @param flag * whether the orientation should be vertical * * @since 2.0 */ // @unused public void setVertical(boolean flag) { if(horizontal != flag) { return; } invalidate(); horizontal = !flag; transposer.setEnabled(horizontal); } /** * Sets the constraint for the given figure. * * @param child * the child * @param constraint * the child's new constraint */ @Override public void setConstraint(IFigure child, Object constraint) { invalidate(child); child.setBorder(null); } }