/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.gef.draw2d;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
/**
* @author Frank Shaka
*/
public class SizeableImageFigure extends ReferencedFigure implements IHasImage {
private static final Rectangle IMAGE_CLIENT_AREA = new Rectangle();
private static final int FLAG_STRETCHED = MAX_FLAG << 1;
private static final int FLAG_CONSTRAINED = MAX_FLAG << 2;
static {
MAX_FLAG = FLAG_CONSTRAINED;
}
private Image img = null;
private Dimension imgSize = null;
private int alpha = -1;
private Insets margins;
/**
* @param parent
*/
public SizeableImageFigure() {
this(null);
}
public SizeableImageFigure(Image image) {
setImage(image);
}
/**
* Sets the Image that this ImageFigure displays.
* <p>
* IMPORTANT: Note that it is the client's responsibility to dispose the
* given image.
*
* @param image
* The Image to be displayed. It can be <code>null</code>.
*/
public void setImage(Image image) {
if (img == image)
return;
img = image;
imgSize = null;
setMinimumSize(new Dimension(1, 1));
revalidate();
repaint();
}
/**
* @return the initial size of the containing image or an empty size if no
* image is set
*/
public Dimension getImageSize() {
if (imgSize == null) {
if (img != null) {
imgSize = new Dimension(img);
} else
imgSize = new Dimension();
}
return imgSize;
}
public boolean isConstrained() {
return getFlag(FLAG_CONSTRAINED);
}
public void setConstrained(boolean constrained) {
if (constrained == isConstrained())
return;
setFlag(FLAG_CONSTRAINED, constrained);
repaint();
}
public boolean isStretched() {
return getFlag(FLAG_STRETCHED);
}
public void setStretched(boolean stretched) {
if (stretched == isStretched())
return;
setFlag(FLAG_STRETCHED, stretched);
repaint();
}
public void setMargins(Insets margins) {
this.margins = margins;
}
/**
* @return The Image that this Figure displays
*/
public Image getImage() {
return img;
}
/**
* @return the alpha
*/
public int getAlpha() {
return alpha;
}
/**
* @see IUseTransparency#DONT_USE_ALPHA
* @param alpha
* the alpha to set
*/
public void setAlpha(int alpha) {
if (this.alpha == alpha)
return;
this.alpha = alpha;
repaint();
}
@Override
public Dimension getPreferredSize(int wHint, int hHint) {
if (prefSize != null)
return prefSize;
if (getLayoutManager() != null) {
Dimension d = getLayoutManager().getPreferredSize(this, wHint,
hHint);
if (d != null)
return d;
}
return calculatePreferredImageSize(wHint, hHint);
}
protected Dimension calculatePreferredImageSize(int wHint, int hHint) {
Dimension size = getImageSize();
if (wHint < 0 && hHint < 0)
return size;
boolean constrained = isConstrained();
boolean stretched = isStretched();
if (constrained || stretched) {
if (size.width == 0 || size.height == 0)
return new Dimension(Math.max(wHint, 0), Math.max(hHint, 0));
if (wHint == 0 || hHint == 0)
return new Dimension(0, 0);
if (wHint > 0 && hHint > 0) {
if (constrained && (stretched || size.width > wHint
|| size.height > hHint)) {
int a = size.width * hHint;
int b = size.height * wHint;
if (stretched ? (a < b) : (a > b)) {
int h = wHint == 0 ? 0 : b / size.width;
return new Dimension(wHint, h);
} else if (stretched ? (a > b) : (a < b)) {
int w = hHint == 0 ? 0 : a / size.height;
return new Dimension(w, hHint);
} else {
return new Dimension(wHint, hHint);
}
} else {
return new Dimension(size.width, size.height);
}
} else if (wHint > 0) {
return new Dimension(wHint, wHint * size.height / size.width);
} else { // if (hHint > 0) {
return new Dimension(hHint * size.width / size.height, hHint);
}
}
return size;
}
/**
* @see org.eclipse.draw2d.Figure#paintFigure(Graphics)
*/
protected void paintFigure(final Graphics graphics) {
super.paintFigure(graphics);
Image image = getImage();
if (image != null) {
graphics.setAntialias(SWT.ON);
if (getAlpha() != IUseTransparency.DONT_USE_ALPHA)
graphics.setAlpha(getAlpha());
paintImage(graphics, image);
}
}
protected void paintImage(Graphics graphics, Image image) {
if (image != null) {
Dimension imageSize;
if (image == this.img)
imageSize = getImageSize();
else {
imageSize = new Dimension(image);
}
paintImage(graphics, image, imageSize,
getImageClientArea(imageSize));
}
}
protected Rectangle getImageClientArea(Dimension imageSize) {
Rectangle area = getClientArea(IMAGE_CLIENT_AREA);
boolean constrained = isConstrained();
boolean stretched = isStretched();
if (constrained && (stretched || imageSize.width > area.width
|| imageSize.height > area.height)) {
adaptAreaToRatio(area, imageSize, stretched);
} else if (!stretched) {
adaptAreaToSize(area, imageSize);
}
if (margins != null) {
return new Rectangle(area.x + margins.left, area.y + margins.top,
Math.max(0, area.width - margins.getWidth()),
Math.max(0, area.height - margins.getHeight()));
} else {
return area;
}
}
protected void adaptAreaToSize(Rectangle area, Dimension size) {
area.x += (area.width - size.width) / 2;
area.width = size.width;
area.y += (area.height - size.height) / 2;
area.height = size.height;
}
protected void adaptAreaToRatio(Rectangle area, Dimension ratio,
boolean bigger) {
int a = ratio.width * area.height;
int b = ratio.height * area.width;
if (bigger ? (a < b) : (a > b)) {
int h = area.width == 0 ? 0 : b / ratio.width;
area.y += (area.height - h) / 2;
area.height = h;
} else if (bigger ? (a > b) : (a < b)) {
int w = area.height == 0 ? 0 : a / ratio.height;
area.x += (area.width - w) / 2;
area.width = w;
}
}
protected void paintImage(Graphics graphics, Image image,
Dimension imageSize, Rectangle clientArea) {
//TODO FIXME
try {
if (clientArea.width == imageSize.width
&& clientArea.height == imageSize.height) {
graphics.drawImage(image, clientArea.x, clientArea.y);
} else {
graphics.drawImage(image, 0, 0, imageSize.width,
imageSize.height, clientArea.x, clientArea.y,
clientArea.width, clientArea.height);
}
} catch (Exception e) {
//TODO FIXME
}
}
}