blob: 039477008726bfb57918e6be70ff8e6a580dd22a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 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
*******************************************************************************/
package org.eclipse.bpel.ui.editparts.borders;
import org.eclipse.bpel.ui.BPELUIPlugin;
import org.eclipse.bpel.ui.IBPELUIConstants;
import org.eclipse.core.resources.IMarker;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.RoundedRectangle;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
/**
* This is the border for sequence, switch, pick and while.
*
* When expanded it displays a label and text at the top as well as showing the
* contents.
*/
public class ContainerBorder extends CollapsableBorder {
// The horizontal margin between the border and the image/text
private static final int leftMargin = 6;
private static final int rightMargin = 10;
// The vertical margin between the border and the image/text
private static final int topMargin = 6;
private static final int bottomMargin = 3;
// space between image and label
static final int spacing = 5;
static final int borderWidth = 1;
static final int margin = 11;
// space between the inside of the border and the contents
static final int hBorderInsets = 3;
static final int vBorderInsets = 22;
// We keep this round rect around to paint.
private RoundedRectangle roundRect;
// The bounds of the "-" icon at the top and bottom of the expanded figure
private Rectangle rectExpandedTop, rectExpandedBottom;
// The calculated bounds of the label and the image when expanded
private Rectangle rectLabel, rectImageLabel;
// The bounds of the round rectangle surrounding the label and image
// when expanded
private Rectangle rectLabelBorder;
// The bounds of the rectangle surrounding the children when expanded.
// Computed to take into account drawers.
private Rectangle expandedBounds;
public ContainerBorder(IFigure parentFigure, Image image, String labelText) {
super(true, IBPELUIConstants.ARC_WIDTH, parentFigure, labelText, image);
this.roundRect = new RoundedRectangle();
this.roundRect.setOpaque(true);
this.roundRect.setCornerDimensions(new Dimension(IBPELUIConstants.ARC_WIDTH, IBPELUIConstants.ARC_WIDTH));
}
public Dimension getPreferredSize(IFigure f) {
calculate(f);
Dimension d = new Dimension(rectLabelBorder.getSize().width, rectLabelBorder.getSize().height + expandedHeight);
d.width += DRAWER_WIDTH * 2;
if (!isCollapsed()) {
d.width += IBPELUIConstants.ARC_WIDTH * 2;
}
return d;
}
protected void doPaint(IFigure figure, Graphics graphics, Insets insets) {
super.doPaint(figure, graphics, insets);
ColorRegistry registry = BPELUIPlugin.getPlugin().getColorRegistry();
graphics.setForegroundColor(registry.get(IBPELUIConstants.COLOR_COMPOSITE_ACTIVITY_BORDER));
if (!isCollapsed()) {
// Paint the round rectangle around the lower part of the figure (surrounding the
// children figures).
graphics.drawRoundRectangle(expandedBounds, IBPELUIConstants.ARC_WIDTH, IBPELUIConstants.ARC_WIDTH);
}
// Paint the round rectangle at the top.
// First determine whether or not square corners are needed on the left edge.
boolean needSquareCorners = (getTopMarker() != null) || (getBottomMarker() != null);
if (isCollapsed() && needSquareCorners) {
// Remember the clipping rectangle
Rectangle oldClip = new Rectangle();
oldClip = graphics.getClip(oldClip);
Rectangle clippingRect = new Rectangle(rectLabelBorder.x + rectLabelBorder.width / 2, rectLabelBorder.y, rectLabelBorder.width / 2 + 2, rectLabelBorder.height + 1);
graphics.setClip(clippingRect);
graphics.drawRoundRectangle(rectLabelBorder, IBPELUIConstants.ARC_WIDTH, IBPELUIConstants.ARC_WIDTH);
clippingRect = new Rectangle(rectLabelBorder.x, rectLabelBorder.y, rectLabelBorder.width / 2 + 1, rectLabelBorder.height + 1);
graphics.setClip(clippingRect);
graphics.drawRectangle(rectLabelBorder);
// Restore the clipping
graphics.setClip(oldClip);
} else {
roundRect.setBounds(rectLabelBorder);
roundRect.setForegroundColor(BPELUIPlugin.getPlugin().getColorRegistry().get(IBPELUIConstants.COLOR_ACTIVITY_BORDER));
roundRect.paint(graphics);
}
Color old = graphics.getForegroundColor();
graphics.setForegroundColor(registry.get(IBPELUIConstants.COLOR_BLACK));
collapsedNameLabel.setBounds(rectLabel);
collapsedNameLabel.paint(graphics);
imageLabel.setBounds(rectImageLabel);
imageLabel.paint(graphics);
graphics.setForegroundColor(old);
if (isCollapsed()) {
graphics.drawImage(collapsedImage, rectCollapsed.getLocation());
} else {
graphics.drawImage(expandedImage, rectExpandedTop.getLocation());
graphics.drawImage(expandedImage, rectExpandedBottom.getLocation());
}
}
// Initialize a bunch of location and size variables based on the contents
protected void calculate(IFigure figure) {
super.calculate(figure);
// bounds of the figure that we are given
Rectangle figureBounds = figure.getBounds().getCopy();
// preferred size of the image
Dimension imageLabelSize = imageLabel.getPreferredSize().getCopy();
// preferred size of the text label
Dimension labelSize = collapsedNameLabel.getPreferredSize().getCopy();
// calculate the label border for the round rectangle
// surrounding the label and image
int w = labelSize.width + spacing + imageLabelSize.width;
int h = Math.max(labelSize.height, imageLabelSize.height);
int x = figureBounds.x + figureBounds.width / 2 - (w/2);
int y = figureBounds.y;
rectLabelBorder = new Rectangle(x, y, w, h);
// expand the border for aesthetics and to account for arc size.
// note we don't use the entire arc size to conserve space.
// also remember we can't expand in the upwards direction.
int verticalMargin = topMargin + bottomMargin;
if (isCollapsed()) verticalMargin--;
rectLabelBorder.expand(new Insets(0, leftMargin, verticalMargin, rightMargin));
// rectangle for image label
x = rectLabelBorder.x + leftMargin;
y = rectLabelBorder.y + topMargin;
w = imageLabelSize.width;
h = imageLabelSize.height;
rectImageLabel = new Rectangle(x, y, w, h);
// rectangle for text label
x = rectLabelBorder.x + leftMargin + imageLabelSize.width + spacing;
y = rectLabelBorder.y + topMargin;
w = labelSize.width;
h = labelSize.height;
rectLabel = new Rectangle(x, y, w, h);
// calculate the size of the round rectangle surrounding the children,
// taking into account arc size and drawer width
this.expandedBounds = figureBounds.getCopy();
// adjust for drawer width
expandedBounds.x += DRAWER_WIDTH;
expandedBounds.width -= DRAWER_WIDTH * 2;
// adjust for half height of the label and image
expandedBounds.y += rectLabelBorder.height / 2;
expandedBounds.height -= rectLabelBorder.height / 2;
// subtract half the height of the minus button at the bottom.
expandedBounds.height -= expandedHeight / 2;
// area for plus/minus buttons
rectExpandedTop = new Rectangle(rectLabelBorder.x + rectLabelBorder.width/2 - expandedWidth/2, rectLabelBorder.y + rectLabelBorder.height - 1, expandedWidth, expandedHeight);
rectExpandedBottom = new Rectangle(figureBounds.x + figureBounds.width / 2 - expandedWidth / 2, figureBounds.y + figureBounds.height - expandedHeight, expandedWidth, expandedHeight);
// Top drawer
IMarker topMarker = getTopMarker();
if (topMarker != null) {
// Draw the image for the top drawer
if (isCollapsed()) {
topDrawerLocation.x = collapsedRectangle.x - DRAWER_WIDTH + DRAWER_INSET + 1;
topDrawerLocation.y = collapsedRectangle.y;
} else {
topDrawerLocation.x = expandedBounds.x - DRAWER_WIDTH;
topDrawerLocation.y = expandedBounds.y + IBPELUIConstants.ARC_WIDTH;
}
}
// Bottom drawer
IMarker bottomMarker = getBottomMarker();
if (bottomMarker != null) {
// Draw the image for the bottom drawer
if (isCollapsed()) {
bottomDrawerLocation.x = collapsedRectangle.x - DRAWER_WIDTH + DRAWER_INSET + 1;
bottomDrawerLocation.y = collapsedRectangle.y + DRAWER_HALF_HEIGHT;
} else {
bottomDrawerLocation.x = expandedBounds.x - DRAWER_WIDTH;
bottomDrawerLocation.y = expandedBounds.y + DRAWER_HALF_HEIGHT + IBPELUIConstants.ARC_WIDTH;
}
}
// Top drawer marker image
Image topImage = getTopImage();
if (topImage != null) {
if (isCollapsed()) {
topImageLocation.x = collapsedRectangle.x - DRAWER_WIDTH + DRAWER_INSET + 2;
topImageLocation.y = collapsedRectangle.y + DRAWER_INSET;
} else {
topImageLocation.x = expandedBounds.x - DRAWER_WIDTH + DRAWER_INSET;
topImageLocation.y = expandedBounds.y + IBPELUIConstants.ARC_WIDTH + DRAWER_INSET;
}
}
// Bottom drawer marker image
Image bottomImage = getBottomImage();
if (bottomImage != null) {
if (isCollapsed()) {
bottomImageLocation.x = collapsedRectangle.x - DRAWER_WIDTH + DRAWER_INSET + 2;
bottomImageLocation.y = collapsedRectangle.y + DRAWER_INSET + DRAWER_HALF_HEIGHT;
} else {
bottomImageLocation.x = expandedBounds.x - DRAWER_WIDTH + DRAWER_INSET;
bottomImageLocation.y = expandedBounds.y + IBPELUIConstants.ARC_WIDTH + DRAWER_HALF_HEIGHT + DRAWER_INSET;
}
}
}
/**
* Compute the insets. We only know how to do this for expanded borders,
* so delegate to super in the collapsed state.
*/
public Insets getInsets(IFigure figure) {
if (isCollapsed()) return super.getInsets(figure);
calculate(figure);
Insets result = new Insets(vBorderInsets + rectLabelBorder.height, hBorderInsets, vBorderInsets, hBorderInsets);
result.left += DRAWER_WIDTH;
result.right += DRAWER_WIDTH;
return result;
}
/**
* throw away values that determine the layout
*/
public void invalidate() {
super.invalidate();
rectLabelBorder = null;
rectLabel = null;
rectExpandedTop = null;
rectExpandedBottom = null;
}
/**
* Tests whether the given point is inside the collapse image. The superclass
* does not know where the collapse image(s) is located.
*/
public boolean isPointInCollapseImage(int x, int y) {
if (isCollapsed()) return super.isPointInCollapseImage(x, y);
Point p = new Point(x,y);
parentFigure.translateToRelative(p);
Rectangle rect = rectExpandedTop.getCopy();
rect.expand(new Insets(1,1,1,1));
if (rect.contains(p)) return true;
if (!isCollapsed()) {
rect = rectExpandedBottom.getCopy();
rect.expand(new Insets(1,1,1,1));
return rect.contains(p);
}
return false;
}
/**
* Provide gradient rectangle.
*/
protected Rectangle getGradientRect() {
if (isCollapsed()) return super.getGradientRect();
invalidate();
calculate(parentFigure);
return expandedBounds;
}
/**
* Edit parts may like to know what the top inset is - this is
* the distance between the top of the border and the top of the
* container round rectangle. This is useful because this is where
* selection handles are often located.
*/
public int getTopInset() {
// HACK! This is necessary to prevent certain NPEs.
if (rectLabelBorder == null || expandedBounds == null) {
calculate(parentFigure);
}
return expandedBounds.y - rectLabelBorder.y;
}
}