/* ****************************************************************************** * 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.Shape; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.jface.util.Util; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Path; import org.eclipse.swt.internal.DPIUtil; import org.eclipse.swt.widgets.Display; import org.xmind.gef.draw2d.geometry.PrecisionDimension; import org.xmind.gef.draw2d.geometry.PrecisionRectangle; /** * @author Frank Shaka */ @SuppressWarnings("restriction") public class PathFigure extends Shape { private static final float[] _bounds = new float[4]; private Path path = null; private boolean outline = true; private boolean fill = true; private int tolerance = 0; /** * */ public PathFigure() { } /** * @return the path */ public Path getPath() { return path; } /** * <b>NOTE:</b> It's client's responsibility to dispose the path. * * @param path * the path to set */ public void setPath(Path path) { if (this.path == path || (this.path != null && this.path.equals(path))) return; this.path = path; setBounds(getPreferredBounds()); // revalidate(); } /** * @return the tolerance */ public int getTolerance() { return tolerance; } /** * @param tolerance * the tolerance to set */ public void setTolerance(int tolerance) { this.tolerance = tolerance; } /** * @see org.eclipse.draw2d.Shape#fillShape(org.eclipse.draw2d.Graphics) */ @Override protected void fillShape(Graphics graphics) { if (path != null) graphics.fillPath(path); } /** * @see org.eclipse.draw2d.Shape#outlineShape(org.eclipse.draw2d.Graphics) */ @Override protected void outlineShape(Graphics graphics) { if (path != null) graphics.drawPath(path); } /** * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int) */ @Override public Dimension getPreferredSize(int wHint, int hHint) { if (path != null) { path.getBounds(_bounds); if (Util.isWindows()) { float[] autoScaleDown = DPIUtil.autoScaleDown(_bounds); _bounds[0] = autoScaleDown[0]; _bounds[1] = autoScaleDown[1]; _bounds[2] = autoScaleDown[2]; _bounds[3] = autoScaleDown[3]; } PrecisionDimension pSize = new PrecisionDimension(_bounds[2], _bounds[3]); double halfLine = getLineWidth() * 0.5d + 1.0; pSize.expand(halfLine, halfLine); return pSize.toDraw2DDimension(); } return super.getPreferredSize(wHint, hHint); } protected Rectangle getPreferredBounds() { if (path == null) return new Rectangle(); path.getBounds(_bounds); if (Util.isWindows()) { float[] autoScaleDown = DPIUtil.autoScaleDown(_bounds); _bounds[0] = autoScaleDown[0]; _bounds[1] = autoScaleDown[1]; _bounds[2] = autoScaleDown[2]; _bounds[3] = autoScaleDown[3]; } PrecisionRectangle pRect = new PrecisionRectangle(_bounds[0], _bounds[1], _bounds[2], _bounds[3]); double halfLine = getLineWidth() * 0.5d; pRect.expand(halfLine, halfLine).resize(1.0, 1.0); return pRect.toDraw2DRectangle(); } /** * @see org.eclipse.draw2d.Figure#containsPoint(int, int) */ @Override public boolean containsPoint(int x, int y) { if (!super.containsPoint(x, y) || path == null || (!hasOutline() && !hasFill())) return false; GC gc = new GC(Display.getCurrent()); gc.setLineWidth(getLineWidth() + tolerance); gc.setLineStyle(getLineStyle()); boolean b = path.contains(x, y, gc, !hasFill()); gc.dispose(); return b; } /** * @see org.eclipse.draw2d.Shape#setOutline(boolean) */ @Override public void setOutline(boolean b) { super.setOutline(b); this.outline = b; } /** * @see org.eclipse.draw2d.Shape#setFill(boolean) */ @Override public void setFill(boolean b) { super.setFill(b); this.fill = b; } public boolean hasOutline() { return outline; } public boolean hasFill() { return fill; } }