/*****************************************************************************
* Copyright (c) 2010 Atos Origin.
*
*
* 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:
* Emilien Perico (Atos Origin) emilien.perico@atosorigin.com - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.activity.locator;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.diagram.ui.figures.IBorderItemLocator;
import org.eclipse.papyrus.uml.diagram.common.locator.AdvancedBorderItemLocator;
public class ActivityParameterNodePositionLocator extends AdvancedBorderItemLocator implements IBorderItemLocator {
/**
* The offset to add to default position. (to avoid corner of rounded
* rectangles)
*/
public static final int EXTRA_BORDER_DEFAULT_OFFSET = 8;
/** The default size of a pin */
public static final int DEFAULT_PIN_SIZE = 16;
protected int borderItemOffset = 10;
/** Constructor **/
public ActivityParameterNodePositionLocator(IFigure parentFigure) {
super(parentFigure);
}
/** Constructor **/
public ActivityParameterNodePositionLocator(IFigure borderItem, IFigure parentFigure, Rectangle constraint) {
super(borderItem, parentFigure, constraint);
}
/** Constructor **/
public ActivityParameterNodePositionLocator(IFigure parentFigure, int preferredSide) {
super(parentFigure, preferredSide);
}
@Override
public Rectangle getValidLocation(Rectangle proposedLocation, IFigure borderItem) {
Rectangle realLocation = new Rectangle(proposedLocation);
int side = findClosestSideOfParent(proposedLocation, getParentBorder());
Point newTopLeft = locateOnBorder(realLocation.getTopLeft(), side, 0, borderItem);
realLocation.setLocation(newTopLeft);
return realLocation;
}
/**
* Find the closest side when x,y is inside parent.
*
* @param proposedLocation
* @param parentBorder
* @return draw constant
*/
public static int findClosestSideOfParent(Rectangle proposedLocation, Rectangle parentBorder) {
int side = AdvancedBorderItemLocator.findClosestSideOfParent(proposedLocation, parentBorder);
// relocate side for North
if(side == PositionConstants.NORTH) {
Point parentCenter = parentBorder.getCenter();
Point childCenter = proposedLocation.getCenter();
if(childCenter.x < parentCenter.x) {
return PositionConstants.WEST;
} else {
return PositionConstants.EAST;
}
}
return side;
}
/**
* Ensure the suggested location actually lies on the parent boundary. The
* side takes precedence.
*
* @param suggestedLocation
* @param suggestedSide
* @return point
*/
protected Point locateOnParent(Point suggestedLocation, int suggestedSide, IFigure borderItem) {
Rectangle bounds = getParentBorder();
int parentFigureWidth = bounds.width;
int parentFigureHeight = bounds.height;
int parentFigureX = bounds.x;
int parentFigureY = bounds.y;
Dimension borderItemSize = getSize(borderItem);
int newX = suggestedLocation.x;
int newY = suggestedLocation.y;
int westX = parentFigureX + getBorderItemOffset().width;
int eastX = parentFigureX + parentFigureWidth - getBorderItemOffset().width - borderItemSize.width;
int southY = parentFigureY + parentFigureHeight - getBorderItemOffset().height - borderItemSize.height;
int northY = parentFigureY + getBorderItemOffset().height + borderItemSize.height;
if(suggestedSide == PositionConstants.WEST) {
if(suggestedLocation.x != westX) {
newX = westX;
}
if(suggestedLocation.y < borderItemSize.height) {
newY = northY + borderItemSize.height;
} else if(suggestedLocation.y > bounds.getBottomLeft().y - borderItemSize.height) {
newY = southY - borderItemSize.height;
}
} else if(suggestedSide == PositionConstants.EAST) {
if(suggestedLocation.x != eastX) {
newX = eastX;
}
if(suggestedLocation.y < borderItemSize.height) {
newY = northY + borderItemSize.height;
} else if(suggestedLocation.y > bounds.getBottomLeft().y - borderItemSize.height) {
newY = southY - borderItemSize.height;
}
} else if(suggestedSide == PositionConstants.SOUTH) {
if(suggestedLocation.y != southY) {
newY = southY;
}
if(suggestedLocation.x < bounds.getBottomLeft().x) {
newX = westX + borderItemSize.width;
} else if(suggestedLocation.x > bounds.getBottomRight().x - borderItemSize.width) {
newX = eastX - borderItemSize.width;
}
} else { // NORTH should not be suggested, consider WEST instead
if(suggestedLocation.x != westX) {
newX = westX;
}
if(suggestedLocation.y < bounds.getTopLeft().y) {
newY = northY + borderItemSize.height;
} else if(suggestedLocation.y > bounds.getBottomLeft().y - borderItemSize.height) {
newY = southY - borderItemSize.height;
}
}
return new Point(newX, newY);
}
@Override
public void relocate(IFigure borderItem) {
// reset bounds of borderItem
Dimension size = getSize(borderItem);
Rectangle rectSuggested = getConstraint().getCopy();
if(rectSuggested.getTopLeft().x == 0 && rectSuggested.getTopLeft().y == 0) {
rectSuggested.setLocation(getPreferredLocation(borderItem));
} else {
// recovered constraint must be translated with the parent location
// to be absolute
rectSuggested.setLocation(rectSuggested.getLocation().translate(getParentBorder().getTopLeft()));
}
rectSuggested.setSize(size);
Rectangle validLocation = getValidLocation(rectSuggested, borderItem);
// the constraint is not reset, but the item bounds are
borderItem.setBounds(validLocation);
// ensure the side property is correctly set
setCurrentSideOfParent(findClosestSideOfParent(borderItem.getBounds(), getParentBorder()));
}
@Override
protected Point getPreferredLocation(int side, IFigure borderItem) {
return super.getPreferredLocation(side, borderItem);
// manage position for in/out parameter
// Rectangle bounds = getParentBorder();
// int parentFigureWidth = bounds.width;
// int parentFigureHeight = bounds.height;
// int parentFigureX = bounds.x;
// int parentFigureY = bounds.y;
// int x = parentFigureX;
// int y = parentFigureY;
//
// Dimension borderItemSize = getSize(borderItem);
// switch(side) {
// case PositionConstants.NORTH:
// x += EXTRA_BORDER_DEFAULT_OFFSET + getBorderItemOffset().width;
// y += -borderItemSize.height + getBorderItemOffset().height;
// break;
// case PositionConstants.EAST:
// // take south east extremity to allow following pins placing above
// x += parentFigureWidth - getBorderItemOffset().width;
// y += parentFigureHeight - borderItemSize.height -
// EXTRA_BORDER_DEFAULT_OFFSET -
// getBorderItemOffset().height;
// break;
// case PositionConstants.SOUTH:
// x += EXTRA_BORDER_DEFAULT_OFFSET + getBorderItemOffset().width;
// y += parentFigureHeight - getBorderItemOffset().height;
// break;
// case PositionConstants.WEST:
// default:
// x += -borderItemSize.width + getBorderItemOffset().width;
// y += EXTRA_BORDER_DEFAULT_OFFSET + getBorderItemOffset().height;
// }
// return new Point(x, y);
}
/**
*
* @param proposedLocation
* the proposed location
* @return a possible location on parent figure border
*/
public Rectangle getPreferredLocation(Rectangle proposedLocation) {
// Initialize port location with proposed location
// and resolve the bounds of it graphical parent
Rectangle realLocation = new Rectangle(proposedLocation);
Rectangle parentRec = getParentFigure().getBounds().getCopy();
// Calculate Max position around the graphical parent (1/2 size or the
// port around
// the graphical parent bounds.
int xMin = parentRec.x - borderItemOffset;
int xMax = parentRec.x - borderItemOffset + parentRec.width;
int yMin = parentRec.y - borderItemOffset;
int yMax = parentRec.y - borderItemOffset + parentRec.height;
// Modify Port location if MAX X or Y are exceeded
if(realLocation.x < xMin) {
realLocation.x = xMin;
}
if(realLocation.x > xMax) {
realLocation.x = xMax;
}
if(realLocation.y < yMin) {
realLocation.y = yMin;
}
if(realLocation.y > yMax) {
realLocation.y = yMax;
}
// Ensure the port is positioned on its parent borders and not in the
// middle.
// Modify position if needed.
if((realLocation.y != yMin) && (realLocation.y != yMax)) {
if((realLocation.x != xMin) && (realLocation.x != xMax)) {
if(realLocation.x <= (xMin + (parentRec.width / 2))) {
realLocation.x = xMin;
} else {
realLocation.x = xMax;
}
}
}
// Return constrained location
return realLocation;
}
}