/* ******************************************************************************
* 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.layers;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformFigure;
import org.eclipse.draw2d.FreeformListener;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ScalableFigure;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.xmind.gef.draw2d.IOriginBased;
import org.xmind.gef.draw2d.IReferencedFigure;
public class ContentsLayer extends BaseLayer implements IOriginBased {
private class ContentsHook implements FreeformListener {
public void notifyFreeformExtentChanged() {
repaint();
}
}
private IFigure contents = null;
private ContentsHook contentsHook = null;
private Point origin = null;
private IFigure topLeft = null;
private IFigure bottomRight = null;
private int margin = 0;
private boolean centered;
private boolean constrained;
public boolean isCentered() {
return centered;
}
public void setCentered(boolean centered) {
if (centered == this.centered)
return;
this.centered = centered;
revalidate();
}
public boolean isConstrained() {
return constrained;
}
public void setConstrained(boolean constrained) {
if (constrained == this.constrained)
return;
this.constrained = constrained;
revalidate();
}
/**
* Have no effect when corners are already added.
*/
public void addCorners() {
if (topLeft == null || topLeft.getParent() != this) {
topLeft = new Figure();
topLeft.setSize(1, 1);
add(topLeft);
}
if (bottomRight == null || bottomRight.getParent() != this) {
bottomRight = new Figure();
bottomRight.setSize(1, 1);
add(bottomRight);
}
}
/**
* Have no effect when corners are already removed.
*/
public void removeCorners() {
if (topLeft != null) {
remove(topLeft);
topLeft = null;
}
if (bottomRight != null) {
remove(bottomRight);
bottomRight = null;
}
}
public IFigure getContents() {
return contents;
}
public void setContents(IFigure fig) {
if (fig == contents)
return;
if (contents != null) {
unhookContents(contents);
remove(contents);
}
contents = fig;
if (contents != null) {
add(contents, 0);
hookContents(contents);
}
}
protected void hookContents(IFigure contents) {
if (contents instanceof FreeformFigure) {
if (contentsHook == null) {
contentsHook = new ContentsHook();
}
((FreeformFigure) contents).addFreeformListener(contentsHook);
}
}
protected void unhookContents(IFigure contents) {
if (contents instanceof FreeformFigure && contentsHook != null) {
((FreeformFigure) contents).removeFreeformListener(contentsHook);
}
}
public Point getOrigin() {
if (origin == null) {
origin = calculateOrigin();
}
return origin;
}
protected Point calculateOrigin() {
if (centered) {
if (topLeft == null || bottomRight == null) {
if (contents != null) {
Rectangle area = getViewportClientArea(this);
if (area != null) {
area = area.getCopy().scale(1 / getScale(this, 1));
Point p = new Point(area.x + (area.width) / 2, area.y
+ (area.height) / 2);
return p;
}
}
}
} else if (constrained) {
if (contents instanceof IReferencedFigure) {
Insets ins = ((IReferencedFigure) contents)
.getReferenceDescription();
Rectangle area = getViewportClientArea(this);
if (area == null) {
area = getBounds();
} else {
area = area.getCopy().scale(1 / getScale(this, 1));
}
return new Point(area.x + (area.width - ins.left - ins.right)
/ 2 + ins.left, area.y
+ (area.height - ins.top - ins.bottom) / 2 + ins.top);
}
return contents.getBounds().getLocation();
}
return new Point();
}
private double getScale(IFigure figure, double scale) {
IFigure parent = figure.getParent();
if (parent instanceof ScalableFigure) {
scale *= ((ScalableFigure) parent).getScale();
}
if (parent != null)
scale = getScale(parent, scale);
return scale;
}
private Rectangle getViewportClientArea(IFigure figure) {
IFigure parent = figure.getParent();
if (parent instanceof Viewport)
return parent.getClientArea();
if (parent != null)
return getViewportClientArea(parent);
return null;
}
public int getMargin() {
return margin;
}
public void setMargin(int margin) {
if (margin == this.margin)
return;
this.margin = margin;
revalidate();
}
protected void layout() {
boolean hasCorners = topLeft != null && bottomRight != null;
if (contents != null) {
layoutContents(hasCorners);
}
if (hasCorners) {
layoutCorner();
}
}
protected void layoutContents(boolean hasCorners) {
if (constrained) {
Dimension size = contents.getPreferredSize();
Rectangle area = getViewportClientArea(this);
if (area == null) {
area = getBounds();
} else {
area = area.getCopy().scale(1 / getScale(this, 1));
}
Rectangle contentBounds = new Rectangle(area.x
+ (area.width - size.width) / 2, area.y
+ (area.height - size.height) / 2, size.width, size.height);
if (contents instanceof FreeformFigure) {
((FreeformFigure) contents).setFreeformBounds(contentBounds);
} else {
contents.setBounds(contentBounds);
}
} else {
Point o = getOrigin();
Insets ins;
if (contents instanceof IReferencedFigure) {
ins = ((IReferencedFigure) contents).getReferenceDescription();
} else {
Dimension size = contents.getPreferredSize();
ins = new Insets(size.height - size.height / 2, size.width
- size.width / 2, size.height / 2, size.width / 2);
}
Rectangle r = new Rectangle(o.x - ins.left, o.y - ins.top, ins
.getWidth(), ins.getHeight());
contents.setBounds(r);
}
}
protected void layoutCorner() {
Point origin = getOrigin();
if (contents != null) {
Rectangle area = getViewportClientArea(this);
if (area != null) {
area = area.getCopy().scale(1 / getScale(this, 1));
Insets ins = getContentsReferenceDescription(true);
int left = origin.x - Math.max(ins.left, area.width);
int top = origin.y - Math.max(ins.top, area.height);
int right = origin.x + Math.max(ins.right, area.width);
int bottom = origin.y + Math.max(ins.bottom, area.height);
topLeft.setLocation(new Point(left, top));
bottomRight.setLocation(new Point(right - 1, bottom - 1));
return;
}
}
topLeft.setLocation(origin);
bottomRight.setLocation(origin);
}
protected Insets getContentsReferenceDescription(boolean hasCorners) {
Insets ins = new Insets(getMargin());
if (contents instanceof IReferencedFigure) {
ins.add(((IReferencedFigure) contents).getReferenceDescription());
} else {
Dimension cSize = contents.getPreferredSize();
ins.right += cSize.width / 2;
ins.bottom += cSize.height / 2;
ins.left += cSize.width - cSize.width / 2;
ins.top += cSize.height - cSize.height / 2;
}
return ins;
}
public void invalidate() {
super.invalidate();
origin = null;
}
}