/* ******************************************************************************
* 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.AncestorListener;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LayoutListener;
import org.xmind.gef.draw2d.graphics.AlphaGraphics;
import org.xmind.gef.draw2d.graphics.ColorMaskGraphics;
import org.xmind.gef.draw2d.graphics.GraphicsUtils;
import org.xmind.gef.draw2d.graphics.GrayedGraphics;
public class ShadowFigure extends Figure {
private class SourceHooker extends LayoutListener.Stub implements
AncestorListener {
public void invalidate(IFigure container) {
super.invalidate(container);
updateVisibility();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.draw2d.AncestorListener#ancestorAdded(org.eclipse.draw2d
* .IFigure)
*/
public void ancestorAdded(IFigure ancestor) {
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.draw2d.AncestorListener#ancestorMoved(org.eclipse.draw2d
* .IFigure)
*/
public void ancestorMoved(IFigure ancestor) {
updateBounds();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.draw2d.AncestorListener#ancestorRemoved(org.eclipse.draw2d
* .IFigure)
*/
public void ancestorRemoved(IFigure ancestor) {
}
}
private static int[] offsets = { 7, 0, 4, 2, 1, 1, 2, 4, //
0, 7, -2, 4, -1, 1, -4, 2, //
-7, 0, -4, -2, -1, -1, -2, -4, //
0, -7, 2, -4, 1, -1, 4, -2 };
//private static int[] offsets = { 1, 1, 2, 0, 1, -1, 0, -2, -1, -2, -2, 0,
//-1, 1, 0, 2 };
//private static int[] offsets = {};
private IFigure source = null;
private int dx = 5;
private int dy = 5;
private int alpha = 0x80;
private SourceHooker sourceHooker = new SourceHooker();
public IFigure getSource() {
return source;
}
public void setSource(IFigure source) {
if (source == this.source)
return;
if (this.source != null) {
this.source.removeLayoutListener(sourceHooker);
this.source.removeAncestorListener(sourceHooker);
}
this.source = source;
if (source != null) {
source.addAncestorListener(sourceHooker);
source.addLayoutListener(sourceHooker);
}
update();
revalidate();
}
public int getOffsetX() {
return dx;
}
public int getOffsetY() {
return dy;
}
public void setOffsetX(int dx) {
setOffset(dx, getOffsetY());
}
public void setOffsetY(int dy) {
setOffset(getOffsetX(), dy);
}
public void setOffset(int dx, int dy) {
boolean translate = (dx != this.dx) || (dy != this.dy);
this.dx = dx;
this.dy = dy;
if (translate) {
updateBounds();
}
}
protected void update() {
updateBounds();
updateVisibility();
}
protected void updateBounds() {
if (source != null) {
setBounds(source.getBounds().getTranslated(getOffsetX(),
getOffsetY()).expand(10, 10));
}
repaint();
}
protected void updateVisibility() {
if (source != null) {
setVisible(source.isShowing());
} else {
setVisible(false);
}
}
public int getAlpha() {
return alpha;
}
public void setAlpha(int alpha) {
if (alpha == this.alpha)
return;
this.alpha = alpha;
repaint();
}
public boolean isVisible() {
return super.isVisible() && isSourceShowing();
}
private boolean isSourceShowing() {
if (source == null)
return false;
if (source instanceof IShadowedFigure)
return ((IShadowedFigure) source).isShadowShowing();
return source.isShowing();
}
public void paint(Graphics graphics) {
GraphicsUtils.fixGradientBugForCarbon(graphics, this);
int mainAlpha = getAlpha();
if (offsets.length > 0) {
int subAlpha = mainAlpha / (offsets.length / 2);
graphics.pushState();
graphics.translate(getOffsetX(), getOffsetY());
for (int i = 0; i < offsets.length - 1; i += 2) {
int offX = offsets[i];
int offY = offsets[i + 1];
graphics.translate(offX, offY);
paintShadow(graphics, subAlpha);
graphics.translate(-offX, -offY);
}
graphics.popState();
} else {
graphics.pushState();
graphics.translate(getOffsetX(), getOffsetY());
paintShadow(graphics, mainAlpha);
graphics.popState();
}
}
protected void paintShadow(Graphics graphics, int alpha) {
AlphaGraphics g1 = new AlphaGraphics(graphics);
g1.setMainAlpha(alpha);
g1.setAlpha(graphics.getAlpha());
if (source instanceof IShadowedFigure) {
((IShadowedFigure) source).paintShadow(g1);
} else {
ColorMaskGraphics g2 = createGlowGraphics(g1);
paintSourceAsShadow(g2);
g2.dispose();
}
g1.dispose();
}
protected void paintSourceAsShadow(Graphics g) {
if (source != null) {
source.paint(g);
}
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.gef.draw2d.GlowFigure#createGlowGraphics(org.eclipse.draw2d
* .Graphics)
*/
protected ColorMaskGraphics createGlowGraphics(Graphics graphics) {
return new GrayedGraphics(graphics);
}
}