blob: 7c97968d2693cf33f3cee4cb9578167a4fc26b5a [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2004, 2010 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.gmf.runtime.draw2d.ui.render.figures;
import java.io.ByteArrayOutputStream;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.ImageFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.draw2d.ui.internal.mapmode.DiagramMapModeUtil;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.draw2d.ui.render.RenderInfo;
import org.eclipse.gmf.runtime.draw2d.ui.render.RenderedImage;
import org.eclipse.gmf.runtime.draw2d.ui.render.factory.RenderedImageFactory;
import org.eclipse.gmf.runtime.draw2d.ui.render.internal.RenderHelper;
import org.eclipse.gmf.runtime.draw2d.ui.render.internal.RenderingListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.RGB;
/**
* An implementation of {@link org.eclipse.draw2d.ImageFigure} that allows
* scaling the underlying image to the containing Figure's bounds, rather then
* being fixed to the image size.
*
* <p>
* Any image that can be implemented inside the RenderedImage interface can be
* supported.
* </p>
*
* @author jcorchis / sshaw
*/
public class ScalableImageFigure
extends ImageFigure {
private RenderingListenerImpl renderingListener = new RenderingListenerImpl();
private class RenderingListenerImpl
implements RenderingListener {
public RenderingListenerImpl() {
super();
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.draw2d.ui.render.internal.RenderingListener#paintFigureWhileRendering(org.eclipse.draw2d.Graphics)
*/
public void paintFigureWhileRendering(Graphics g) {
ScalableImageFigure.this.paintFigureWhileRendering(g);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.draw2d.ui.render.RenderingListener#imageRendered(org.eclipse.gmf.runtime.draw2d.ui.render.RenderedImage)
*/
public void imageRendered(RenderedImage rndImg) {
if (ScalableImageFigure.this.getParent() != null) {
ScalableImageFigure.this.setRenderedImage(rndImg);
ScalableImageFigure.this.repaint();
}
}
/**
* @return <code>IFigure</code> that the listener wraps
*/
public ScalableImageFigure getFigure() {
return ScalableImageFigure.this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (obj instanceof RenderingListenerImpl) {
return ((RenderingListenerImpl) obj).getFigure().equals(
getFigure());
}
return false;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return ScalableImageFigure.this.hashCode();
}
}
/** The preferred size of the image */
private Dimension preferredSize = new Dimension(-1, -1);
private static final int FLAG_USE_DEFAULT_IMAGESIZE = MAX_FLAG << 1,
FLAG_MAINTAIN_ASPECT_RATIO = MAX_FLAG << 2,
FLAG_ANTI_ALIAS = MAX_FLAG << 3,
FLAG_USE_ORIGINAL_COLORS = MAX_FLAG << 4;
/** The last rendered <code>RenderedImage</code> */
private RenderedImage lastRenderedImage = null;
/**
* Accessor to determine if the rendered image will be anti-aliased (if
* possible).
*
* @return <code>boolean</code> <code>true</code> if anti aliasing is
* on, <code>false</code> otherwise.
*/
public boolean isAntiAlias() {
return getFlag(FLAG_ANTI_ALIAS);
}
/**
* Sets a property to determine if the rendered image will be anti-aliased
* (if possible).
*
* @param antiAlias
* <code>boolean</code> <code>true</code> if anti-aliasing is
* to be turned on, <code>false</code> otherwise
*/
public void setAntiAlias(boolean antiAlias) {
setFlag(FLAG_ANTI_ALIAS, antiAlias);
invalidate();
}
/**
* Accessor to determine if the rendered image will respect the original
* aspect ratio of the default image when resized.
*
* @return <code>boolean</code> <code>true</code> if maintain aspect
* ratio is on, <code>false</code> otherwise.
*/
public boolean isMaintainAspectRatio() {
return getFlag(FLAG_MAINTAIN_ASPECT_RATIO);
}
/**
* Sets a property to determine if the rendered image will respect the
* original aspect ratio of the default image when resized.
*
* @param maintainAspectRatio
* <code>boolean</code> <code>true</code> if maintain aspect
* ratio is to be turned on, <code>false</code> otherwise
*/
public void setMaintainAspectRatio(boolean maintainAspectRatio) {
setFlag(FLAG_MAINTAIN_ASPECT_RATIO, maintainAspectRatio);
invalidate();
}
/**
* @param img
* the <code>Image</code> to render
*/
public ScalableImageFigure(Image img) {
ImageLoader imageLoader = new ImageLoader();
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
imageLoader.data = new ImageData[] {img.getImageData()};
imageLoader.logicalScreenHeight = img.getBounds().width;
imageLoader.logicalScreenHeight = img.getBounds().height;
imageLoader.save(byteOS, SWT.IMAGE_BMP);
this.lastRenderedImage = RenderedImageFactory.getInstance(byteOS
.toByteArray());
setFlag(FLAG_USE_DEFAULT_IMAGESIZE, false);
setFlag(FLAG_USE_ORIGINAL_COLORS, false);
setFlag(FLAG_MAINTAIN_ASPECT_RATIO, true);
setFlag(FLAG_ANTI_ALIAS, true);
}
/**
* @param renderedImage
*/
public ScalableImageFigure(RenderedImage renderedImage) {
this(renderedImage, false, false, true);
}
/**
* Constructor for meta image sources.
*
* @param renderedImage
* the <code>RenderedImage</code> that is used for rendering
* the image.
*/
public ScalableImageFigure(RenderedImage renderedImage, boolean antiAlias) {
this(renderedImage, false, false, antiAlias);
}
/**
* Constructor for meta image sources.
*
* @param renderedImage
* the <code>RenderedImage</code> that is used for rendering
* the image.
* @param useDefaultImageSize
* <code>boolean</code> indicating whether to initialize the
* preferred size with the default image size. Otherwise, a set
* default will be used instead.
* @param useOriginalColors
* <code>boolean</code> indicating whether to use the original
* colors of the <code>RenderedImage</code> or to replace black
* with outline color and white with the fill color.
*/
public ScalableImageFigure(RenderedImage renderedImage,
boolean useDefaultImageSize, boolean useOriginalColors,
boolean antiAlias) {
lastRenderedImage = renderedImage;
setFlag(FLAG_USE_DEFAULT_IMAGESIZE, useDefaultImageSize);
setFlag(FLAG_USE_ORIGINAL_COLORS, useOriginalColors);
setFlag(FLAG_MAINTAIN_ASPECT_RATIO, true);
setFlag(FLAG_ANTI_ALIAS, antiAlias);
}
/**
* Sets the preferred size of the image figure.
*
* @param w
* the preferred width of the image
* @param h
* the preferred height of the image
*/
public void setPreferredImageSize(int w, int h) {
preferredSize = new Dimension(w, h);
}
/**
* Returns the size set specified by setPreferredImageSize() or the size
* specified by the image. In the case of meta-images a preferred size of
* 32x32 is returned.
*/
public Dimension getPreferredSize(int wHint, int hHint) {
if (preferredSize.height == -1 && preferredSize.width == -1) {
int extent = MapModeUtil.getMapMode(this).DPtoLP(32);
preferredSize = new Dimension(extent, extent);
if (getFlag(FLAG_USE_DEFAULT_IMAGESIZE)) {
if (getRenderedImage() != null) {
setRenderedImage(getRenderedImage(new Dimension(0, 0)));
Image swtImage = null;
if (getRenderedImage() != null)
swtImage = getRenderedImage().getSWTImage();
if (swtImage != null) {
org.eclipse.swt.graphics.Rectangle imgRect = swtImage
.getBounds();
preferredSize.width = MapModeUtil.getMapMode(this)
.DPtoLP(imgRect.width);
preferredSize.height = MapModeUtil.getMapMode(this)
.DPtoLP(imgRect.height);
}
}
}
}
return preferredSize;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
*/
public void setBounds(Rectangle rect) {
Dimension devDim = new Dimension(rect.getSize());
MapModeUtil.getMapMode(this).LPtoDP(devDim);
if (getRenderedImage() != null) {
setRenderedImage(getRenderedImage(devDim));
}
super.setBounds(rect);
}
/**
* Override to return an image that is scaled to fit the bounds of the
* figure.
*/
public Image getImage() {
if (getRenderedImage() == null)
return null;
return getRenderedImage().getSWTImage();
}
/**
* Gets the <code>RenderedImage</code> that is the for the specified
* <code>Dimension</code>
*
* @param dim
* @return the <code>RenderedImage</code>
*/
private RenderedImage getRenderedImage(Dimension dim) {
Color fill = getBackgroundColor();
Color outline = getForegroundColor();
RenderInfo newRenderInfo = getRenderedImage().getRenderInfo();
newRenderInfo.setValues(dim.width,
dim.height,
isMaintainAspectRatio(), // maintain aspect ratio
isAntiAlias(),
useOriginalColors() ? (RGB)null
: new RGB(fill.getRed(), fill.getGreen(), fill.getBlue()),
useOriginalColors() ? (RGB)null
: new RGB(outline.getRed(), outline.getGreen(), outline.getBlue())); // antialias
RenderedImage newRenderedImage = getRenderedImage()
.getNewRenderedImage(newRenderInfo);
return newRenderedImage;
}
/**
* @return a <code>boolean</code> <code>true</code> if the original
* colors of the image should be used for rendering, or
* <code>false</code> indicates that black and white colors can
* replaced by the specified outline and fill colors respectively of
* the <code>RenderInfo</code>.
*/
public boolean useOriginalColors() {
return getFlag(FLAG_USE_ORIGINAL_COLORS);
}
/**
* If the rendering is occuring on a separate thread, this method is a hook to draw a temporary
* image onto the drawing surface.
*
* @param g the <code>Graphics</code> object to paint the temporary image to
*/
protected void paintFigureWhileRendering(Graphics g) {
Rectangle area = getClientArea().getCopy();
g.pushState();
g.setBackgroundColor(ColorConstants.white);
g.fillRectangle(area.x, area.y, area.width - 1, area.height - 1);
g.setForegroundColor(ColorConstants.red);
g.drawRectangle(area.x, area.y, area.width - 1, area.height - 1);
g.setLineStyle(SWT.LINE_DOT);
g.drawLine(area.x, area.y, area.x + area.width, area.y
+ area.height);
g.drawLine(area.x + area.width, area.y, area.x, area.y
+ area.height);
g.popState();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics)
*/
protected void paintFigure(Graphics graphics) {
Rectangle area = getClientArea().getCopy();
RenderInfo rndInfo = getRenderedImage().getRenderInfo();
if (!useOriginalColors()) {
RGB backgroundColor = getBackgroundColor().getRGB();
RGB foregroundColor = getForegroundColor().getRGB();
if ((backgroundColor != null && !backgroundColor.equals(rndInfo.getBackgroundColor())) ||
(foregroundColor != null && !foregroundColor.equals(rndInfo.getForegroundColor()))) {
rndInfo.setValues(rndInfo.getWidth(), rndInfo.getHeight(),
rndInfo.shouldMaintainAspectRatio(),
rndInfo.shouldAntiAlias(), getBackgroundColor().getRGB(), getForegroundColor().getRGB());
setRenderedImage(getRenderedImage().getNewRenderedImage(rndInfo));
}
}
setRenderedImage(RenderHelper.getInstance(
DiagramMapModeUtil.getScale(MapModeUtil.getMapMode(this)), false,
false, null).drawRenderedImage(graphics, getRenderedImage(), area,
renderingListener));
}
/**
* Gets the <code>RenderedImage</code> that is being displayed by this
* figure.
*
* @return <code>RenderedImage</code> that is being displayed by this
* figure.
*/
public RenderedImage getRenderedImage() {
return lastRenderedImage;
}
/**
* Sets the <code>RenderedImage</code> that is to be displayed by this
* figure
*
* @param the
* <code>RenderedImage</code> that is to being displayed by
* this figure
*/
public void setRenderedImage(RenderedImage renderedImage) {
if (this.lastRenderedImage != renderedImage) {
this.lastRenderedImage = renderedImage;
if (renderedImage == null || renderedImage.isRendered()) {
notifyImageChanged();
}
}
}
}