/* * Copyright (c) 2006 Borland Software Corporation * * 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: * Sergey Gribovsky (Borland) - initial API and implementation */ package org.eclipse.papyrus.uml.diagram.common.draw2d; import java.util.HashMap; 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; public class LaneLayout extends AbstractHintLayout { public static int HORIZONTAL = 0; public static int VERTICAL = 1; private static final Insets NO_INSETS = new Insets(0, 0, 0, 0); private int myLaneOrientation; private Insets myInsets; // Transposer object used in layout calculations private final Transposer myTransposer; private final HashMap<IFigure, Object> myConstraints; // @unused public LaneLayout() { this(HORIZONTAL, NO_INSETS); } // @unused public LaneLayout(Insets insets) { this(HORIZONTAL, insets); } public LaneLayout(int laneOrientation, Insets insets) { myConstraints = new HashMap<IFigure, Object>(); myTransposer = new Transposer(); setLaneOrientation(laneOrientation); setInsets(insets); } public void setLaneOrientation(int orientation) { if(orientation != HORIZONTAL && orientation != VERTICAL) { throw new IllegalArgumentException("Incorrect lane orientation constant: " + orientation); //$NON-NLS-1$ } myTransposer.setEnabled(orientation == VERTICAL); myLaneOrientation = orientation; } public int getLaneOrientation() { return myLaneOrientation; } public void setInsets(Insets insets) { myInsets = insets != null ? insets : NO_INSETS; } public Insets getInsets() { return myInsets; } @Override protected Dimension calculateMinimumSize(IFigure container, int wHint, int hHint) { Insets insets = container.getInsets(); List children = container.getChildren(); int childWHint = getLaneOrientation() == HORIZONTAL ? Math.max(0, wHint - insets.getWidth()) : (wHint - insets.getWidth() > 0 ? wHint - insets.getWidth() / children.size() : wHint); int childHHint = getLaneOrientation() == VERTICAL ? Math.max(0, hHint - insets.getHeight()) : (hHint - insets.getHeight() > 0 ? hHint - insets.getHeight() / children.size() : hHint); int height = 0, width = 0; for(int i = 0; i < children.size(); i++) { IFigure child = (IFigure)children.get(i); Rectangle constraint = (Rectangle)getConstraint(child); Dimension childSize = myTransposer.t(myTransposer.t(constraint).height > -1 ? constraint.getSize() : child.getMinimumSize(childWHint, childHHint)); height += childSize.height; width = Math.max(width, childSize.width); } return myTransposer.t(new Dimension(width, height)).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container)); } @Override protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) { Insets insets = container.getInsets(); List children = container.getChildren(); int childWHint = getLaneOrientation() == HORIZONTAL ? Math.max(0, wHint - insets.getWidth()) : (wHint - insets.getWidth() > 0 ? wHint - insets.getWidth() / children.size() : wHint); int childHHint = getLaneOrientation() == VERTICAL ? Math.max(0, hHint - insets.getHeight()) : (hHint - insets.getHeight() > 0 ? hHint - insets.getHeight() / children.size() : hHint); int height = 0, width = 0; for(int i = 0; i < children.size(); i++) { IFigure child = (IFigure)children.get(i); Rectangle constraint = (Rectangle)getConstraint(child); Dimension childSize = myTransposer.t(myTransposer.t(constraint).height > -1 ? constraint.getSize() : child.getPreferredSize(childWHint, childHHint)); height += childSize.height; width = Math.max(width, childSize.width); } return myTransposer.t(new Dimension(width, height)).expand(insets.getWidth(), insets.getHeight()).union(getBorderPreferredSize(container)); } @Override public void setConstraint(IFigure child, Object constraint) { super.setConstraint(child, constraint); if(constraint != null) { myConstraints.put(child, constraint); } } @Override public Object getConstraint(IFigure child) { return myConstraints.get(child); } @Override public void remove(IFigure child) { super.remove(child); myConstraints.remove(child); } public void layout(IFigure container) { List children = container.getChildren(); int numChildren = children.size(); if(numChildren > 0) { Dimension prefSizes[] = new Dimension[numChildren]; Dimension minSizes[] = new Dimension[numChildren]; Insets insets = getInsets(); int wHint = getLaneOrientation() == HORIZONTAL ? Math.max(0, container.getClientArea(Rectangle.SINGLETON).width - insets.getWidth()) : -1; int hHint = getLaneOrientation() == VERTICAL ? Math.max(0, container.getClientArea(Rectangle.SINGLETON).height - insets.getHeight()) : -1; int totalPrefHeight = 0; int nonExpansibleNum = 0; for(int i = 0; i < numChildren; i++) { IFigure child = (IFigure)children.get(i); Rectangle constraint = (Rectangle)getConstraint(child); boolean isResizedByUser = myTransposer.t(constraint).height > -1; prefSizes[i] = myTransposer.t(isResizedByUser ? constraint.getSize() : child.getPreferredSize(wHint, hHint)); minSizes[i] = myTransposer.t(isResizedByUser ? constraint.getSize() : child.getMinimumSize(wHint, hHint)); totalPrefHeight += prefSizes[i].height; if(isResizedByUser) { nonExpansibleNum++; } } Rectangle clientArea = myTransposer.t(container.getClientArea().getCopy().crop(insets)); int expansion = totalPrefHeight < clientArea.height && children.size() > nonExpansibleNum ? (clientArea.height - totalPrefHeight) / (children.size() - nonExpansibleNum) : 0; int x = clientArea.x; int y = clientArea.y; for(int i = 0; i < numChildren; i++) { int prefHeight = prefSizes[i].height; int prefWidth = prefSizes[i].width; int minWidth = minSizes[i].width; Rectangle newBounds = new Rectangle(x, y, prefWidth, prefHeight); IFigure child = (IFigure)children.get(i); Rectangle constraint = myTransposer.t((Rectangle)getConstraint(child)); boolean isResizedByUser = constraint.height > -1; newBounds.width = Math.max(minWidth, clientArea.width); if(isResizedByUser) { /* * If all element are resized by user and summary preferred * heigh is less then client area, last element should cover * spare space. */ if(numChildren == nonExpansibleNum && totalPrefHeight < clientArea.height && i == numChildren - 1) { newBounds.height += clientArea.height - totalPrefHeight; } } else { newBounds.height += expansion; } child.setBounds(myTransposer.t(newBounds)); y += newBounds.height; } } } }