/****************************************************************************** * 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(); } } } }