/* ******************************************************************************
* 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.ui.internal.fishbone.decorations;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.xmind.gef.draw2d.geometry.Geometry;
import org.xmind.gef.draw2d.geometry.IPrecisionTransformer;
import org.xmind.gef.draw2d.geometry.PrecisionHorizontalFlipper;
import org.xmind.gef.draw2d.geometry.PrecisionLine;
import org.xmind.gef.draw2d.geometry.PrecisionLine.LineType;
import org.xmind.gef.draw2d.geometry.PrecisionPoint;
import org.xmind.gef.draw2d.graphics.Path;
import org.xmind.ui.decorations.AbstractTopicDecoration;
public class FishheadTopicDecoration extends AbstractTopicDecoration {
private static final PrecisionPoint p1 = new PrecisionPoint();
private static final PrecisionPoint p2 = new PrecisionPoint();
private IPrecisionTransformer f = new PrecisionHorizontalFlipper();
private static final float headGapScale = 0.8f;
protected static final float headConScale = 0.3f;
private static final float headHorScale = 0.3f;
private static final float headVerScale = 0.5f;
public FishheadTopicDecoration(boolean rightHeaded) {
f.setEnabled(rightHeaded);
}
protected void sketch(IFigure figure, Path shape, Rectangle box,
int purpose) {
Insets ins = figure.getInsets();
Rectangle clientArea = box.getShrinked(ins);
f.setOrigin(box.x + box.width * 0.5, box.y + box.height * 0.5);
int right = box.right();
int bottom = box.bottom();
float x = box.x
+ clientArea.width * FishheadTopicDecoration.headConScale;
float y = box.y + box.height * 0.5f;
f.tp(right, box.y, p1);
shape.moveTo((float) p1.x, (float) p1.y);
f.tp(x, box.y, p1);
f.tp(box.x, y, p2);
shape.quadTo((float) p1.x, (float) p1.y, (float) p2.x, (float) p2.y);
f.tp(x, bottom, p1);
f.tp(right, bottom, p2);
shape.quadTo((float) p1.x, (float) p1.y, (float) p2.x, (float) p2.y);
shape.close();
}
public PrecisionPoint getAnchorLocation(IFigure figure, double refX,
double refY, double expansion) {
Insets ins = figure.getInsets();
Rectangle box = figure.getBounds();
f.setOrigin(box.x + box.width * 0.5, box.y + box.height * 0.5);
Rectangle clientArea = box.getShrinked(ins);
int right = box.right();
int bottom = box.bottom();
float cx = box.x
+ clientArea.width * FishheadTopicDecoration.headConScale;
float ey = box.y + box.height * 0.5f;
PrecisionPoint center = getReferencePoint(figure, new PrecisionPoint());
PrecisionLine line = new PrecisionLine(f.tp(center.x, center.y, p1),
f.tp(refX, refY, p2), LineType.Ray);
PrecisionLine rightBorder = new PrecisionLine(right, box.y, right,
bottom, LineType.LineSegment);
PrecisionPoint p = line.intersect(rightBorder);
if (p != null)
return f.r(p);
PrecisionPoint[] ps = Geometry.intersectQuadBezier(line, right, box.y,
cx, box.y, box.x, ey);
if (ps.length > 0)
return f.r(ps[0]);
ps = Geometry.intersectQuadBezier(line, box.x, ey, cx, bottom, right,
bottom);
if (ps.length > 0)
return f.r(ps[0]);
return f.rp(box.x, box.y);
}
public Insets getPreferredInsets(IFigure figure, int width, int height) {
int v = (int) (height * FishheadTopicDecoration.headVerScale);
int r = f.isEnabled() ? hor(getRightMargin(), width)
: gap(getRightMargin());
int l = f.isEnabled() ? gap(getLeftMargin())
: hor(getLeftMargin(), width);
return new Insets(v + getTopMargin() + getLineWidth(),
l + getLineWidth(), v + getBottomMargin() + getLineWidth(),
r + getLineWidth());
}
private int hor(int margin, int wHint) {
return (int) (wHint * FishheadTopicDecoration.headHorScale) + margin;
}
private int gap(int margin) {
return (int) (margin * FishheadTopicDecoration.headGapScale);
}
}