blob: 25c4a10484c4013d1088b53574885c49ebc3412d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2012 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.ImageFigure;
import org.eclipse.draw2d.Label;
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.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.Image;
/**
* This border knows about collapsability. Specifically, it has icons for expand
* and collapse, does hit testing for these icons, has an image and label to use
* when collapsed, and does complete rendering when collapsed to look similar to
* a leaf border (except with the addition of an expand icon).
*
* It does not do rendering for the expanded state. The rationale is that things
* should look similar when collapsed (like a leaf node) but may have different
* appearances when expanded.
*/
public abstract class CollapsableBorder extends GradientBorder {
// Whether or not we are collapsed.
private boolean collapsed = false;
// The location of the collapsed image (+).
protected Rectangle rectCollapsed;
// The images for collapsed (+) and expanded (-).
protected Image collapsedImage, expandedImage;
// The width and height of the expanded image. Collapsed should be the same.
protected int expandedWidth, expandedHeight;
// The label to use when collapsed. Subclasses may also use it when expanded.
protected Label collapsedNameLabel = null;
// The image to use when collapsed. Subclasses may also use it when expanded.
protected Image image;
// The label containing the image.
protected ImageFigure imageLabel = null;
// Our parent figure. Used for relative location calculation.
protected IFigure parentFigure;
// The calculated rectangle for the collapsed border. This is null
// when not collapsed, so subclasses shouldn't assume it's there.
protected Rectangle collapsedBounds;
// The calculated location of the top and bottom drawer images as well as
// the top and bottom drawers themselves.
protected Point topImageLocation = new Point(), bottomImageLocation = new Point();
protected Point topDrawerLocation = new Point(), bottomDrawerLocation = new Point();
// The calculated bounds of the rectangle to draw when collapsed
protected Rectangle collapsedRectangle;
public CollapsableBorder(boolean isVertical, int arcWidth, IFigure parentFigure, String labelText, Image image) {
super(isVertical, arcWidth);
this.parentFigure = parentFigure;
this.image = image;
this.imageLabel = new ImageFigure(image);
this.collapsedImage = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_FIGURE_COLLAPSED);
this.expandedImage = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_FIGURE_EXPANDED);
this.expandedHeight = expandedImage.getBounds().height;
this.expandedWidth = expandedImage.getBounds().width;
this.collapsedNameLabel = new Label(labelText);
this.collapsedNameLabel.setFont(JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT));
}
/**
* Tests whether the given point is inside the collapsed image.
* The superclass only knows where the collapsed image is located; if subclasses
* want to do hit testing on the expanded image, they may override but may want
* to call super if we are collapsed.
*/
public boolean isPointInCollapseImage(int x, int y) {
if (!isCollapsed()) return false;
Point p = new Point(x,y);
parentFigure.translateToRelative(p);
Rectangle rect = rectCollapsed.getCopy();
rect.expand(new Insets(1,1,1,1));
return rect.contains(p);
}
public boolean isCollapsed() {
return collapsed;
}
public void setCollapsed(boolean showCollapse) {
this.collapsed = showCollapse;
}
/**
* Throw away computed values that determine the layout
*/
public void invalidate() {
// rectCollapsed = null;
collapsedBounds = null;
}
public Label getLabel() {
return collapsedNameLabel;
}
public void setName(String name) {
collapsedNameLabel.setText(name);
}
protected void calculate(IFigure figure) {
// Calculate the coordinates for collapsed state, even though
// we may currently be expanded.
if (collapsedBounds == null) {
collapsedBounds = figure.getBounds().getCopy();
this.collapsedRectangle = collapsedBounds.getCopy();
// Leave room on the left and right for the drawer.
collapsedRectangle.x += DRAWER_WIDTH;
collapsedRectangle.width -= DRAWER_WIDTH * 2;
// area for collapsed button
rectCollapsed = new Rectangle(collapsedBounds.x + collapsedBounds.width / 2 - expandedWidth/2, collapsedBounds.y + collapsedBounds.height - expandedHeight, expandedWidth, expandedHeight);
}
}
/**
* This method first invalidates and recalculates any bounds, and then
* paints the top and bottom drawers, as well as any markers contained within them.
*/
@Override
public final void paint(IFigure figure, Graphics graphics, Insets insets) {
invalidate();
calculate(figure);
doPaint(figure, graphics, insets);
}
/**
* Subclasses should call this paint method unless there is a very good
* reason for overriding its behaviour. To affect where various things
* appear, override the calculate() method.
*/
protected void doPaint(IFigure figure, Graphics graphics, Insets insets) {
// Remember the clipping rectangle
Rectangle oldClip = new Rectangle();
oldClip = graphics.getClip(oldClip);
IMarker topMarker = getTopMarker();
IMarker bottomMarker = getBottomMarker();
if (topMarker != null || bottomMarker != null) {
ColorRegistry registry = BPELUIPlugin.INSTANCE.getColorRegistry();
graphics.setForegroundColor(registry.get(IBPELUIConstants.COLOR_ACTIVITY_BORDER));
Rectangle clippingRect;
if (bottomMarker == null) {
clippingRect = new Rectangle(topDrawerLocation.x, topDrawerLocation.y, DRAWER_WIDTH, DRAWER_HALF_HEIGHT + 1);
} else if (topMarker == null) {
clippingRect = new Rectangle(bottomDrawerLocation.x, bottomDrawerLocation.y, DRAWER_WIDTH, DRAWER_HALF_HEIGHT + 1);
} else {
clippingRect = new Rectangle(topDrawerLocation.x, topDrawerLocation.y, DRAWER_WIDTH, DRAWER_HEIGHT + 1);
}
graphics.setClip(clippingRect);
// -1 due to GEF
graphics.drawRoundRectangle(new Rectangle(topDrawerLocation.x + DRAWER_INSET, topDrawerLocation.y, DRAWER_WIDTH * 2, DRAWER_HEIGHT - 1), IBPELUIConstants.ARC_WIDTH, IBPELUIConstants.ARC_WIDTH);
graphics.setClip(oldClip);
if (bottomMarker == null || topMarker == null) {
graphics.drawLine(topDrawerLocation.x + DRAWER_INSET, topDrawerLocation.y + DRAWER_HALF_HEIGHT, topDrawerLocation.x + DRAWER_WIDTH, topDrawerLocation.y + DRAWER_HALF_HEIGHT);
}
}
// Draw the actual breakpoints
Image topImage = getTopImage();
if (topImage != null) {
graphics.drawImage(topImage, topImageLocation);
}
Image bottomImage = getBottomImage();
if (bottomImage != null) {
graphics.drawImage(bottomImage, bottomImageLocation);
}
}
/**
* We only know about the gradient rectangle when we are collapsed.
* TODO: Do we need a gradient rectangle when collapsed?
*/
@Override
protected Rectangle getGradientRect() {
return new Rectangle(0,0,0,0);
}
@Override
public boolean isPointInTopDrawer(int x, int y) {
if (getTopMarker() == null) return false;
Point p = new Point(x, y);
Image image = getTopImage();
org.eclipse.swt.graphics.Rectangle imageSize = image.getBounds();
Rectangle imageBounds = new Rectangle(topImageLocation.x, topImageLocation.y, imageSize.width, imageSize.height);
return imageBounds.contains(p);
}
@Override
public boolean isPointInBottomDrawer(int x, int y) {
if (getBottomMarker() == null) return false;
Point p = new Point(x, y);
Image image = getBottomImage();
org.eclipse.swt.graphics.Rectangle imageSize = image.getBounds();
Rectangle imageBounds = new Rectangle(bottomImageLocation.x, bottomImageLocation.y, imageSize.width, imageSize.height);
return imageBounds.contains(p);
}
/**
* Calculate the insets when in the collapsed state. In expanded state, we don't
* know how to answer. Insets don't matter in the collapsed state because there
* are no children.
*/
@Override
public Insets getInsets(IFigure figure) {
return new Insets(0, 0, 0, 0);
}
}